diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs index 934d9818ce..fa4970f855 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/EventManager.cs @@ -46,21 +46,26 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine public class EventManager : iScriptEngineFunctionModule { // - // Class is instanced in "ScriptEngine" and Uses "EventQueueManager" that is also instanced in "ScriptEngine". + // Class is instanced in "ScriptEngine" and Uses "EventQueueManager" + // that is also instanced in "ScriptEngine". // This class needs a bit of explaining: // - // This class it the link between an event inside OpenSim and the corresponding event in a user script being executed. + // This class it the link between an event inside OpenSim and + // the corresponding event in a user script being executed. // - // For example when an user touches an object then the "myScriptEngine.World.EventManager.OnObjectGrab" event is fired inside OpenSim. - // We hook up to this event and queue a touch_start in EventQueueManager with the proper LSL parameters. + // For example when an user touches an object then the + // "myScriptEngine.World.EventManager.OnObjectGrab" event is fired + // inside OpenSim. + // We hook up to this event and queue a touch_start in + // EventQueueManager with the proper LSL parameters. // It will then be delivered to the script by EventQueueManager. // - // You can check debug C# dump of an LSL script if you need to verify what exact parameters are needed. + // You can check debug C# dump of an LSL script if you need to + // verify what exact parameters are needed. // - private ScriptEngine myScriptEngine; - //public IScriptHost TEMP_OBJECT_ID; + public EventManager(ScriptEngine _ScriptEngine, bool performHookUp) { myScriptEngine = _ScriptEngine; @@ -74,28 +79,34 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine public void HookUpEvents() { - // Hook up to events from OpenSim - // We may not want to do it because someone is controlling us and will deliver events to us + myScriptEngine.Log.Info("[" + myScriptEngine.ScriptEngineName + + "]: Hooking up to server events"); - myScriptEngine.Log.Info("[" + myScriptEngine.ScriptEngineName + "]: Hooking up to server events"); - myScriptEngine.World.EventManager.OnObjectGrab += touch_start; - myScriptEngine.World.EventManager.OnObjectDeGrab += touch_end; - myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript; - myScriptEngine.World.EventManager.OnScriptChangedEvent += changed; - myScriptEngine.World.EventManager.OnScriptAtTargetEvent += at_target; - myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent += not_at_target; - myScriptEngine.World.EventManager.OnScriptControlEvent += control; - myScriptEngine.World.EventManager.OnScriptColliderStart += collision_start; - myScriptEngine.World.EventManager.OnScriptColliding += collision; - myScriptEngine.World.EventManager.OnScriptCollidingEnd += collision_end; + myScriptEngine.World.EventManager.OnObjectGrab += + touch_start; + myScriptEngine.World.EventManager.OnObjectDeGrab += + touch_end; + myScriptEngine.World.EventManager.OnRemoveScript += + OnRemoveScript; + myScriptEngine.World.EventManager.OnScriptChangedEvent += + changed; + myScriptEngine.World.EventManager.OnScriptAtTargetEvent += + at_target; + myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent += + not_at_target; + myScriptEngine.World.EventManager.OnScriptControlEvent += + control; + myScriptEngine.World.EventManager.OnScriptColliderStart += + collision_start; + myScriptEngine.World.EventManager.OnScriptColliding += + collision; + myScriptEngine.World.EventManager.OnScriptCollidingEnd += + collision_end; - // TODO: HOOK ALL EVENTS UP TO SERVER! - IMoneyModule money=myScriptEngine.World.RequestModuleInterface(); + IMoneyModule money = + myScriptEngine.World.RequestModuleInterface(); if (money != null) - { money.OnObjectPaid+=HandleObjectPaid; - } - } public void ReadConfig() @@ -104,7 +115,9 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine private void HandleObjectPaid(UUID objectID, UUID agentID, int amount) { - SceneObjectPart part=myScriptEngine.World.GetSceneObjectPart(objectID); + SceneObjectPart part = + myScriptEngine.World.GetSceneObjectPart(objectID); + if (part != null) { money(part.LocalId, agentID, amount); @@ -127,8 +140,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine new DetectParams[0])); } - public void touch_start(uint localID, uint originalID, Vector3 offsetPos, - IClientAPI remoteClient) + public void touch_start(uint localID, uint originalID, + Vector3 offsetPos, IClientAPI remoteClient) { // Add to queue for all scripts in ObjectID object DetectParams[] det = new DetectParams[1]; @@ -138,7 +151,9 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine if (originalID == 0) { - SceneObjectPart part = myScriptEngine.World.GetSceneObjectPart(localID); + SceneObjectPart part = + myScriptEngine.World.GetSceneObjectPart(localID); + if (part == null) return; @@ -146,7 +161,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine } else { - SceneObjectPart originalPart = myScriptEngine.World.GetSceneObjectPart(originalID); + SceneObjectPart originalPart = + myScriptEngine.World.GetSceneObjectPart(originalID); det[0].LinkNum = originalPart.LinkNum; } @@ -196,7 +212,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine if (originalID == 0) { - SceneObjectPart part = myScriptEngine.World.GetSceneObjectPart(localID); + SceneObjectPart part = + myScriptEngine.World.GetSceneObjectPart(localID); if (part == null) return; @@ -204,7 +221,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine } else { - SceneObjectPart originalPart = myScriptEngine.World.GetSceneObjectPart(originalID); + SceneObjectPart originalPart = + myScriptEngine.World.GetSceneObjectPart(originalID); det[0].LinkNum = originalPart.LinkNum; } @@ -213,9 +231,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine det)); } - public void OnRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine) + public void OnRezScript(uint localID, UUID itemID, string script, + int startParam, bool postOnRez, string engine) { - List engines = new List(myScriptEngine.World.RequestModuleInterfaces()); + List engines = + new List( + myScriptEngine.World.RequestModuleInterfaces()); List names = new List(); foreach (IScriptModule m in engines) @@ -228,7 +249,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine string firstline = script.Substring(0, lineEnd).Trim(); int colon = firstline.IndexOf(':'); - if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1) + if (firstline.Length > 2 && + firstline.Substring(0, 2) == "//" && colon != -1) { string engineName = firstline.Substring(2, colon-2); @@ -237,15 +259,43 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine engine = engineName; script = "//" + script.Substring(script.IndexOf(':')+1); } + else + { + if (engine == myScriptEngine.ScriptEngineName) + { + SceneObjectPart part = + myScriptEngine.World.GetSceneObjectPart( + localID); + + TaskInventoryItem item = + part.GetInventoryItem(itemID); + + ScenePresence presence = + myScriptEngine.World.GetScenePresence( + item.OwnerID); + + if (presence != null) + { + presence.ControllingClient.SendAgentAlertMessage( + "Selected engine unavailable. "+ + "Running script on "+ + myScriptEngine.ScriptEngineName, + false); + } + } + } } } if (engine != myScriptEngine.ScriptEngineName) return; - myScriptEngine.Log.Debug("OnRezScript localID: " + localID + " LLUID: " + itemID.ToString() + " Size: " + - script.Length); - myScriptEngine.m_ScriptManager.StartScript(localID, itemID, script, startParam, postOnRez); + myScriptEngine.Log.Debug("OnRezScript localID: " + localID + + " LLUID: " + itemID.ToString() + " Size: " + + script.Length); + + myScriptEngine.m_ScriptManager.StartScript(localID, itemID, script, + startParam, postOnRez); } public void OnRemoveScript(uint localID, UUID itemID) diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs index db3f89f6d5..a9de5035ee 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/EventQueueThreadClass.cs @@ -34,20 +34,18 @@ using System.Globalization; using OpenMetaverse; using log4net; using OpenSim.Framework; +using OpenSim.Region.Environment.Scenes; using OpenSim.Region.Environment.Scenes.Scripting; +using OpenSim.Region.ScriptEngine.Shared; namespace OpenSim.Region.ScriptEngine.DotNetEngine { - /// - /// Because every thread needs some data set for it (time started to execute current function), it will do its work within a class - /// + // Because every thread needs some data set for it + // (time started to execute current function), it will do its work + // within a class public class EventQueueThreadClass : iScriptEngineFunctionModule { - // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// How many ms to sleep if queue is empty - /// + // How many ms to sleep if queue is empty private static int nothingToDoSleepms;// = 50; private static ThreadPriority MyThreadPriority; @@ -77,13 +75,17 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine { lock (ScriptEngine.ScriptEngines) { - foreach (ScriptEngine m_ScriptEngine in ScriptEngine.ScriptEngines) + foreach (ScriptEngine m_ScriptEngine in + ScriptEngine.ScriptEngines) { ScriptEngineName = m_ScriptEngine.ScriptEngineName; - nothingToDoSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("SleepTimeIfNoScriptExecutionMs", 50); + nothingToDoSleepms = + m_ScriptEngine.ScriptConfigSource.GetInt( + "SleepTimeIfNoScriptExecutionMs", 50); + + string pri = m_ScriptEngine.ScriptConfigSource.GetString( + "ScriptThreadPriority", "BelowNormal"); - // Later with ScriptServer we might want to ask OS for stuff too, so doing this a bit manually - string pri = m_ScriptEngine.ScriptConfigSource.GetString("ScriptThreadPriority", "BelowNormal"); switch (pri.ToLower()) { case "lowest": @@ -102,9 +104,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine MyThreadPriority = ThreadPriority.Highest; break; default: - MyThreadPriority = ThreadPriority.BelowNormal; // Default - m_ScriptEngine.Log.Error("[ScriptEngine.DotNetEngine]: Unknown priority type \"" + pri + - "\" in config file. Defaulting to \"BelowNormal\"."); + MyThreadPriority = ThreadPriority.BelowNormal; + m_ScriptEngine.Log.Error( + "[ScriptEngine.DotNetEngine]: Unknown "+ + "priority type \"" + pri + + "\" in config file. Defaulting to "+ + "\"BelowNormal\"."); break; } } @@ -128,41 +133,41 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine EventQueueThread.Start(); ThreadTracker.Add(EventQueueThread); - // Look at this... Don't you wish everyone did that solid coding everywhere? :P + // Look at this... Don't you wish everyone did that solid + // coding everywhere? :P + if (ThreadCount == int.MaxValue) ThreadCount = 0; + ThreadCount++; } public void Stop() { - //PleaseShutdown = true; // Set shutdown flag - //Thread.Sleep(100); // Wait a bit if (EventQueueThread != null && EventQueueThread.IsAlive == true) { try { EventQueueThread.Abort(); // Send abort - //EventQueueThread.Join(); // Wait for it } catch (Exception) { - //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Exception killing worker thread: " + e.ToString()); } } } - private EventQueueManager.QueueItemStruct BlankQIS = new EventQueueManager.QueueItemStruct(); + private EventQueueManager.QueueItemStruct BlankQIS = + new EventQueueManager.QueueItemStruct(); + private ScriptEngine lastScriptEngine; - /// - /// Queue processing thread loop - /// + private uint lastLocalID; + + // Queue processing thread loop private void EventQueueThreadLoop() { CultureInfo USCulture = new CultureInfo("en-US"); Thread.CurrentThread.CurrentCulture = USCulture; - //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread spawned"); try { while (true) @@ -177,205 +182,181 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine catch (ThreadAbortException) { if (lastScriptEngine != null) - lastScriptEngine.Log.Info("[" + ScriptEngineName + "]: ThreadAbortException while executing function."); + lastScriptEngine.Log.Info("[" + ScriptEngineName + + "]: ThreadAbortException while executing "+ + "function."); + } + catch (SelfDeleteException) // Must delete SOG + { + SceneObjectPart part = + lastScriptEngine.World.GetSceneObjectPart( + lastLocalID); + + if (part != null && part.ParentGroup != null) + lastScriptEngine.World.DeleteSceneObject( + part.ParentGroup); } catch (Exception e) { if (lastScriptEngine != null) - lastScriptEngine.Log.Error("[" + ScriptEngineName + "]: Exception in EventQueueThreadLoop: " + e.ToString()); + lastScriptEngine.Log.Error("[" + ScriptEngineName + + "]: Exception in EventQueueThreadLoop: " + + e.ToString()); } } } catch (ThreadAbortException) { - //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: EventQueueManager Worker thread killed: " + tae.Message); } } public void DoProcessQueue() { - //lock (ScriptEngine.ScriptEngines) - //{ - foreach (ScriptEngine m_ScriptEngine in new ArrayList(ScriptEngine.ScriptEngines)) + foreach (ScriptEngine m_ScriptEngine in + new ArrayList(ScriptEngine.ScriptEngines)) + { + lastScriptEngine = m_ScriptEngine; + + EventQueueManager.QueueItemStruct QIS = BlankQIS; + bool GotItem = false; + + //if (PleaseShutdown) + // return; + + if (m_ScriptEngine.m_EventQueueManager == null || + m_ScriptEngine.m_EventQueueManager.eventQueue == null) + continue; + + if (m_ScriptEngine.m_EventQueueManager.eventQueue.Count == 0) { - lastScriptEngine = m_ScriptEngine; - // Every now and then check if we should shut down - //if (PleaseShutdown || EventQueueManager.ThreadsToExit > 0) - //{ - // // Someone should shut down, lets get exclusive lock - // lock (EventQueueManager.ThreadsToExitLock) - // { - // // Lets re-check in case someone grabbed it - // if (EventQueueManager.ThreadsToExit > 0) - // { - // // Its crowded here so we'll shut down - // EventQueueManager.ThreadsToExit--; - // Stop(); - // return; - // } - // else - // { - // // We have been asked to shut down - // Stop(); - // return; - // } - // } - //} + // Nothing to do? Sleep a bit waiting for something to do + Thread.Sleep(nothingToDoSleepms); + } + else + { + // Something in queue, process - //try - // { - EventQueueManager.QueueItemStruct QIS = BlankQIS; - bool GotItem = false; - - //if (PleaseShutdown) - // return; - - if (m_ScriptEngine.m_EventQueueManager == null || m_ScriptEngine.m_EventQueueManager.eventQueue == null) - continue; - - if (m_ScriptEngine.m_EventQueueManager.eventQueue.Count == 0) + // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME + // OBJECT IS NOT GOOD + lock (m_ScriptEngine.m_EventQueueManager.eventQueue) { - // Nothing to do? Sleep a bit waiting for something to do - Thread.Sleep(nothingToDoSleepms); - } - else - { - // Something in queue, process - //myScriptEngine.Log.Info("[" + ScriptEngineName + "]: Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName); - - // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD - lock (m_ScriptEngine.m_EventQueueManager.eventQueue) + GotItem = false; + for (int qc = 0; qc < m_ScriptEngine.m_EventQueueManager.eventQueue.Count; qc++) { - GotItem = false; - for (int qc = 0; qc < m_ScriptEngine.m_EventQueueManager.eventQueue.Count; qc++) - { - // Get queue item - QIS = m_ScriptEngine.m_EventQueueManager.eventQueue.Dequeue(); + // Get queue item + QIS = m_ScriptEngine.m_EventQueueManager.eventQueue.Dequeue(); - // Check if object is being processed by someone else - if (m_ScriptEngine.m_EventQueueManager.TryLock(QIS.localID) == false) - { - // Object is already being processed, requeue it - m_ScriptEngine.m_EventQueueManager.eventQueue.Enqueue(QIS); - } - else - { - // We have lock on an object and can process it - GotItem = true; - break; - } + // Check if object is being processed by + // someone else + if (m_ScriptEngine.m_EventQueueManager.TryLock( + QIS.localID) == false) + { + // Object is already being processed, requeue it + m_ScriptEngine.m_EventQueueManager. + eventQueue.Enqueue(QIS); + } + else + { + // We have lock on an object and can process it + GotItem = true; + break; } } + } - if (GotItem == true) + if (GotItem == true) + { + // Execute function + try { - // Execute function + // Only pipe event if land supports it. + if (m_ScriptEngine.World.PipeEventsForScript( + QIS.localID)) + { + lastLocalID = QIS.localID; + LastExecutionStarted = DateTime.Now.Ticks; + KillCurrentScript = false; + InExecution = true; + m_ScriptEngine.m_ScriptManager.ExecuteEvent( + QIS.localID, + QIS.itemID, + QIS.functionName, + QIS.llDetectParams, + QIS.param); + + InExecution = false; + } + } + catch (Exception e) + { + InExecution = false; + // DISPLAY ERROR INWORLD + string text = "Error executing script function \"" + + QIS.functionName + "\":\r\n"; + + if (e.InnerException != null) + { + // Send inner exception + string line = " (unknown line)"; + Regex rx = new Regex(@"SecondLife\.Script\..+[\s:](?\d+)\.?\r?$", RegexOptions.Compiled); + if (rx.Match(e.InnerException.ToString()).Success) + line = " (line " + rx.Match(e.InnerException.ToString()).Result("${line}") + ")"; + text += e.InnerException.Message.ToString() + line; + } + else + { + text += "\r\n"; + // Send normal + text += e.Message.ToString(); + } + if (KillCurrentScript) + text += "\r\nScript will be deactivated!"; + try { - ///cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined -#if DEBUG - //eventQueueManager.m_ScriptEngine.Log.Debug("[" + ScriptEngineName + "]: " + - // "Executing event:\r\n" - // + "QIS.localID: " + QIS.localID - // + ", QIS.itemID: " + QIS.itemID - // + ", QIS.functionName: " + - // QIS.functionName); -#endif - // Only pipe event if land supports it. - if (m_ScriptEngine.World.PipeEventsForScript(QIS.localID)) - { - LastExecutionStarted = DateTime.Now.Ticks; - KillCurrentScript = false; - InExecution = true; - m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, - QIS.itemID, - QIS.functionName, - QIS.llDetectParams, - QIS.param); - InExecution = false; - } + if (text.Length > 1500) + text = text.Substring(0, 1500); + IScriptHost m_host = + m_ScriptEngine.World.GetSceneObjectPart(QIS.localID); + m_ScriptEngine.World.SimChat( + Utils.StringToBytes(text), + ChatTypeEnum.DebugChannel, 2147483647, + m_host.AbsolutePosition, + m_host.Name, m_host.UUID, false); } - catch (Exception e) + catch (Exception) { - InExecution = false; - // DISPLAY ERROR INWORLD - string text = "Error executing script function \"" + QIS.functionName + - "\":\r\n"; - if (e.InnerException != null) - { - // Send inner exception - string line = " (unknown line)"; - Regex rx = new Regex(@"SecondLife\.Script\..+[\s:](?\d+)\.?\r?$", RegexOptions.Compiled); - if (rx.Match(e.InnerException.ToString()).Success) - line = " (line " + rx.Match(e.InnerException.ToString()).Result("${line}") + ")"; - text += e.InnerException.Message.ToString() + line; - } - else - { - text += "\r\n"; - // Send normal - text += e.Message.ToString(); - } - if (KillCurrentScript) - text += "\r\nScript will be deactivated!"; - - try - { - if (text.Length > 1500) - text = text.Substring(0, 1500); - IScriptHost m_host = - m_ScriptEngine.World.GetSceneObjectPart(QIS.localID); - //if (m_host != null) - //{ - m_ScriptEngine.World.SimChat(Utils.StringToBytes(text), - ChatTypeEnum.DebugChannel, 2147483647, - m_host.AbsolutePosition, - m_host.Name, m_host.UUID, false); - } - catch (Exception) - { - //} - //else - //{ - // T oconsole - m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.Log.Error("[" + ScriptEngineName + - "]: " + - "Unable to send text in-world:\r\n" + - text); - } - finally - { - // So we are done sending message in-world - if (KillCurrentScript) - { - m_ScriptEngine.m_EventQueueManager.m_ScriptEngine.m_ScriptManager.StopScript( - QIS.localID, QIS.itemID); - } - } - - // Pass it on so it's displayed on the console - // and in the logs (mikem 2008.06.02). - throw e.InnerException; + m_ScriptEngine.m_EventQueueManager. + m_ScriptEngine.Log.Error("[" + + ScriptEngineName + "]: " + + "Unable to send text in-world:\r\n" + + text); } finally { - InExecution = false; - m_ScriptEngine.m_EventQueueManager.ReleaseLock(QIS.localID); + // So we are done sending message in-world + if (KillCurrentScript) + { + m_ScriptEngine.m_EventQueueManager. + m_ScriptEngine.m_ScriptManager. + StopScript( + QIS.localID, QIS.itemID); + } } + + // Pass it on so it's displayed on the console + // and in the logs (mikem 2008.06.02). + throw e.InnerException; + } + finally + { + InExecution = false; + m_ScriptEngine.m_EventQueueManager.ReleaseLock( + QIS.localID); } } } - // } + } } - - ///// - ///// If set to true then threads and stuff should try to make a graceful exit - ///// - //public bool PleaseShutdown - //{ - // get { return _PleaseShutdown; } - // set { _PleaseShutdown = value; } - //} - //private bool _PleaseShutdown = false; } } diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs index fca4617b8c..b5938941e5 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs @@ -439,13 +439,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine #region Perform event execution in script - /// - /// Execute a LL-event-function in Script - /// - /// Object the script is located in - /// Script ID - /// Name of function - /// Arguments to pass to function + // Execute a LL-event-function in Script internal void ExecuteEvent(uint localID, UUID itemID, string FunctionName, DetectParams[] qParams, object[] args) { @@ -454,8 +448,10 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine return; detparms[id] = qParams; + if (id.Running) id.Script.ExecuteEvent(id.State, FunctionName, args); + detparms.Remove(id); } diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 3a06462b59..044803061a 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -356,6 +356,31 @@ namespace OpenSim.Region.ScriptEngine.XEngine engine = engineName; script = "//" + script.Substring(script.IndexOf(':')+1); } + else + { + if (engine == ScriptEngineName) + { + SceneObjectPart part = + m_Scene.GetSceneObjectPart( + localID); + + TaskInventoryItem item = + part.GetInventoryItem(itemID); + + ScenePresence presence = + m_Scene.GetScenePresence( + item.OwnerID); + + if (presence != null) + { + presence.ControllingClient.SendAgentAlertMessage( + "Selected engine unavailable. "+ + "Running script on "+ + ScriptEngineName, + false); + } + } + } } }