Add per-instance date to DNE to avoid serializing stuff 10 times a second.

Clode cleanup and removal of commented stuff in ScriptManager.
0.6.0-stable
Melanie Thielker 2008-09-26 15:01:03 +00:00
parent 77eac708fa
commit 24628928c3
7 changed files with 180 additions and 250 deletions

View File

@ -43,22 +43,22 @@ namespace OpenSim.Region.ScriptEngine.Common
} }
protected override scriptEvents DoGetStateEventFlags() protected override scriptEvents DoGetStateEventFlags(string state)
{ {
// Console.WriteLine("Get event flags for " + m_Script.State); // Console.WriteLine("Get event flags for " + state);
// Check to see if we've already computed the flags for this state // Check to see if we've already computed the flags for this state
scriptEvents eventFlags = scriptEvents.None; scriptEvents eventFlags = scriptEvents.None;
if (m_stateEvents.ContainsKey(m_Script.State)) if (m_stateEvents.ContainsKey(state))
{ {
m_stateEvents.TryGetValue(m_Script.State, out eventFlags); m_stateEvents.TryGetValue(state, out eventFlags);
return eventFlags; return eventFlags;
} }
// Fill in the events for this state, cache the results in the map // Fill in the events for this state, cache the results in the map
foreach (KeyValuePair<string, scriptEvents> kvp in m_eventFlagsMap) foreach (KeyValuePair<string, scriptEvents> kvp in m_eventFlagsMap)
{ {
string evname = m_Script.State + "_event_" + kvp.Key; string evname = state + "_event_" + kvp.Key;
Type type = m_Script.GetType(); Type type = m_Script.GetType();
try try
{ {
@ -75,16 +75,16 @@ namespace OpenSim.Region.ScriptEngine.Common
} }
// Save the flags we just computed and return the result // Save the flags we just computed and return the result
m_stateEvents.Add(m_Script.State, eventFlags); m_stateEvents.Add(state, eventFlags);
return (eventFlags); return (eventFlags);
} }
protected override void DoExecuteEvent(string FunctionName, object[] args) protected override void DoExecuteEvent(string state, string FunctionName, object[] args)
{ {
// IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory. // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
// Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead! // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
string EventName = m_Script.State + "_event_" + FunctionName; string EventName = state + "_event_" + FunctionName;
//#if DEBUG //#if DEBUG
// Console.WriteLine("ScriptEngine: Script event function name: " + EventName); // Console.WriteLine("ScriptEngine: Script event function name: " + EventName);

View File

@ -140,28 +140,23 @@ namespace OpenSim.Region.ScriptEngine.Common
/// </summary> /// </summary>
/// <param name="FunctionName">Name of function to execute</param> /// <param name="FunctionName">Name of function to execute</param>
/// <param name="args">Arguments to pass to function</param> /// <param name="args">Arguments to pass to function</param>
public void ExecuteEvent(string FunctionName, object[] args) public void ExecuteEvent(string state, string FunctionName, object[] args)
{ {
if (m_Running == false) DoExecuteEvent(state, FunctionName, args);
{
// Script is inactive, do not execute!
return;
}
DoExecuteEvent(FunctionName, args);
} }
protected abstract void DoExecuteEvent(string FunctionName, object[] args); protected abstract void DoExecuteEvent(string state, string FunctionName, object[] args);
/// <summary> /// <summary>
/// Compute the events handled by the current state of the script /// Compute the events handled by the current state of the script
/// </summary> /// </summary>
/// <returns>state mask</returns> /// <returns>state mask</returns>
public scriptEvents GetStateEventFlags() public scriptEvents GetStateEventFlags(string state)
{ {
return DoGetStateEventFlags(); return DoGetStateEventFlags(state);
} }
protected abstract scriptEvents DoGetStateEventFlags(); protected abstract scriptEvents DoGetStateEventFlags(string state);
/// <summary> /// <summary>
/// Stop script from running. Event execution will be ignored. /// Stop script from running. Event execution will be ignored.

View File

@ -32,10 +32,7 @@ namespace OpenSim.Region.ScriptEngine.Common
{ {
public interface IScript public interface IScript
{ {
string State { get; set; }
int StartParam { get; set; }
ExecutorBase Exec { get; } ExecutorBase Exec { get; }
string Source { get; set; }
void InitApi(string api, IScriptApi LSL_Functions); void InitApi(string api, IScriptApi LSL_Functions);
} }
} }

View File

@ -74,12 +74,6 @@ namespace OpenSim.Region.ScriptEngine.Common
private string m_state = "default"; private string m_state = "default";
public String State
{
get { return m_state; }
set { m_state = value; }
}
public void state(string newState) public void state(string newState)
{ {
m_LSL_Functions.state(newState); m_LSL_Functions.state(newState);
@ -98,22 +92,6 @@ namespace OpenSim.Region.ScriptEngine.Common
public ILSL_Api m_LSL_Functions; public ILSL_Api m_LSL_Functions;
public IOSSL_Api m_OSSL_Functions; public IOSSL_Api m_OSSL_Functions;
private string _Source = String.Empty;
public string Source
{
get
{
return _Source;
}
set { _Source = value; }
}
private int m_StartParam = 0;
public int StartParam
{
get { return m_StartParam; }
set { m_StartParam = value; }
}
public ScriptBaseClass() public ScriptBaseClass()
{ {

View File

@ -188,7 +188,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
} }
} }
public IScript LoadScript(string FileName) public IScript LoadScript(string FileName, out AppDomain ad)
{ {
// Find next available AppDomain to put it in // Find next available AppDomain to put it in
AppDomainStructure FreeAppDomain = GetFreeAppDomain(); AppDomainStructure FreeAppDomain = GetFreeAppDomain();
@ -201,6 +201,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script"); FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
//Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt)); //Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
FreeAppDomain.ScriptsLoaded++; FreeAppDomain.ScriptsLoaded++;
ad = FreeAppDomain.CurrentAppDomain;
return mbrt; return mbrt;
} }

View File

@ -198,12 +198,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
if (localID == 0) if (localID == 0)
return null; return null;
IScript Script = m_ScriptManager.GetScript(localID, itemID); InstanceData id = m_ScriptManager.GetScript(localID, itemID);
if (Script == null) if (id == null)
return null; return null;
DetectParams[] det = m_ScriptManager.GetDetectParams(Script); DetectParams[] det = m_ScriptManager.GetDetectParams(id);
if (number < 0 || number >= det.Length) if (number < 0 || number >= det.Length)
return null; return null;
@ -223,12 +223,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
if (localID == 0) if (localID == 0)
return; return;
IScript Script = m_ScriptManager.GetScript(localID, itemID); InstanceData id = m_ScriptManager.GetScript(localID, itemID);
if (Script == null) if (id == null)
return; return;
string currentState = Script.State; string currentState = id.State;
if (currentState != state) if (currentState != state)
{ {
@ -239,22 +239,29 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
} }
catch (AppDomainUnloadedException) catch (AppDomainUnloadedException)
{ {
Console.WriteLine("[SCRIPT]: state change called when script was unloaded. Nothing to worry about, but noting the occurance"); Console.WriteLine("[SCRIPT]: state change called when "+
"script was unloaded. Nothing to worry about, "+
"but noting the occurance");
} }
Script.State = state; id.State = state;
try try
{ {
int eventFlags = m_ScriptManager.GetStateEventFlags(localID, itemID); int eventFlags = m_ScriptManager.GetStateEventFlags(localID,
itemID);
SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID); SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID);
if (part != null) if (part != null)
part.SetScriptEvents(itemID, eventFlags); part.SetScriptEvents(itemID, eventFlags);
m_EventManager.state_entry(localID); m_EventManager.state_entry(localID);
} }
catch (AppDomainUnloadedException) catch (AppDomainUnloadedException)
{ {
Console.WriteLine("[SCRIPT]: state change called when script was unloaded. Nothing to worry about, but noting the occurance"); Console.WriteLine("[SCRIPT]: state change called when "+
"script was unloaded. Nothing to worry about, but "+
"noting the occurance");
} }
} }
} }
@ -265,11 +272,11 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
if (localID == 0) if (localID == 0)
return false; return false;
IScript script = m_ScriptManager.GetScript(localID, itemID); InstanceData id = m_ScriptManager.GetScript(localID, itemID);
if (script == null) if (id == null)
return false; return false;
return script.Exec.Running?true:false; return id.Running;
} }
public void SetScriptState(UUID itemID, bool state) public void SetScriptState(UUID itemID, bool state)
@ -278,11 +285,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
if (localID == 0) if (localID == 0)
return; return;
IScript script = m_ScriptManager.GetScript(localID, itemID); InstanceData id = m_ScriptManager.GetScript(localID, itemID);
if (script == null) if (id == null)
return; return;
script.Exec.Running = state; if (!id.Disabled)
id.Running = state;
} }
public void ApiResetScript(UUID itemID) public void ApiResetScript(UUID itemID)

View File

@ -41,6 +41,17 @@ using System.Threading;
namespace OpenSim.Region.ScriptEngine.DotNetEngine namespace OpenSim.Region.ScriptEngine.DotNetEngine
{ {
public class InstanceData
{
public IScript Script;
public string State;
public bool Running;
public bool Disabled;
public string Source;
public int StartParam;
public AppDomain AppDomain;
}
public class ScriptManager public class ScriptManager
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@ -49,13 +60,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
private Thread scriptLoadUnloadThread; private Thread scriptLoadUnloadThread;
private static Thread staticScriptLoadUnloadThread; private static Thread staticScriptLoadUnloadThread;
// private int scriptLoadUnloadThread_IdleSleepms;
private Queue<LUStruct> LUQueue = new Queue<LUStruct>(); private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
private static bool PrivateThread; private static bool PrivateThread;
private int LoadUnloadMaxQueueSize; private int LoadUnloadMaxQueueSize;
private Object scriptLock = new Object(); private Object scriptLock = new Object();
private bool m_started = false; private bool m_started = false;
private Dictionary<IScript, DetectParams[]> detparms = new Dictionary<IScript, DetectParams[]>(); private Dictionary<InstanceData, DetectParams[]> detparms =
new Dictionary<InstanceData, DetectParams[]>();
// Load/Unload structure // Load/Unload structure
private struct LUStruct private struct LUStruct
@ -75,15 +86,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
Unload = 2 Unload = 2
} }
// Xantor 20080525: Keep a list of compiled scripts this session for reuse public Dictionary<UUID, String> scriptList =
public Dictionary<UUID, String> scriptList = new Dictionary<UUID, string>(); new Dictionary<UUID, string>();
// Object<string, Script<string, script>> public Dictionary<uint, Dictionary<UUID, InstanceData>> Scripts =
// IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory. new Dictionary<uint, Dictionary<UUID, InstanceData>>();
// Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
public Dictionary<uint, Dictionary<UUID, IScript>> Scripts =
new Dictionary<uint, Dictionary<UUID, IScript>>();
private Compiler.LSL.Compiler LSLCompiler;
public Scene World public Scene World
{ {
@ -91,7 +100,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
} }
#endregion #endregion
private Compiler.LSL.Compiler LSLCompiler;
public void Initialize() public void Initialize()
{ {
@ -99,21 +107,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
LSLCompiler = new Compiler.LSL.Compiler(m_scriptEngine); LSLCompiler = new Compiler.LSL.Compiler(m_scriptEngine);
} }
// KEEP TRACK OF SCRIPTS <int id, whatever script> public void _StartScript(uint localID, UUID itemID, string Script,
//internal Dictionary<uint, Dictionary<UUID, LSL_BaseClass>> Scripts = new Dictionary<uint, Dictionary<UUID, LSL_BaseClass>>(); int startParam, bool postOnRez)
// LOAD SCRIPT
// UNLOAD SCRIPT
// PROVIDE SCRIPT WITH ITS INTERFACE TO OpenSim
public void _StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[{0}]: ScriptManager StartScript: localID: {1}, itemID: {2}", "[{0}]: ScriptManager StartScript: localID: {1}, itemID: {2}",
m_scriptEngine.ScriptEngineName, localID, itemID); m_scriptEngine.ScriptEngineName, localID, itemID);
//IScriptHost root = host.GetRoot();
// We will initialize and start the script. // We will initialize and start the script.
// It will be up to the script itself to hook up the correct events. // It will be up to the script itself to hook up the correct events.
string CompiledScriptFile = String.Empty; string CompiledScriptFile = String.Empty;
@ -123,13 +123,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
if (null == m_host) if (null == m_host)
{ {
m_log.ErrorFormat( m_log.ErrorFormat(
"[{0}]: Could not find scene object part corresponding to localID {1} to start script", "[{0}]: Could not find scene object part corresponding "+
"to localID {1} to start script",
m_scriptEngine.ScriptEngineName, localID); m_scriptEngine.ScriptEngineName, localID);
return; return;
} }
// Xantor 20080525: I need assetID here to see if we already compiled this one previously
UUID assetID = UUID.Zero; UUID assetID = UUID.Zero;
TaskInventoryItem taskInventoryItem = new TaskInventoryItem(); TaskInventoryItem taskInventoryItem = new TaskInventoryItem();
if (m_host.TaskInventory.TryGetValue(itemID, out taskInventoryItem)) if (m_host.TaskInventory.TryGetValue(itemID, out taskInventoryItem))
@ -137,122 +137,135 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
try try
{ {
// Xantor 20080525 see if we already compiled this script this session, stop incessant recompiling on
// scriptreset, spawning of objects with embedded scripts etc.
if (scriptList.TryGetValue(assetID, out CompiledScriptFile)) if (scriptList.TryGetValue(assetID, out CompiledScriptFile))
{ {
m_log.InfoFormat("[SCRIPT]: Found existing compile of assetID {0}: {1}", assetID, CompiledScriptFile); m_log.InfoFormat("[SCRIPT]: Found existing compile of "+
"assetID {0}: {1}", assetID, CompiledScriptFile);
} }
else else
{ {
// Compile (We assume LSL) // Compile (We assume LSL)
CompiledScriptFile = LSLCompiler.PerformScriptCompile(Script); CompiledScriptFile =
LSLCompiler.PerformScriptCompile(Script);
// Xantor 20080525 Save compiled scriptfile for later use m_log.InfoFormat("[SCRIPT]: Compiled assetID {0}: {1}",
m_log.InfoFormat("[SCRIPT]: Compiled assetID {0}: {1}", assetID, CompiledScriptFile); assetID, CompiledScriptFile);
scriptList.Add(assetID, CompiledScriptFile); scriptList.Add(assetID, CompiledScriptFile);
} }
//#if DEBUG InstanceData id = new InstanceData();
//long before;
//before = GC.GetTotalMemory(true); // This force a garbage collect that freezes some windows plateforms
//#endif
IScript CompiledScript; IScript CompiledScript;
CompiledScript = m_scriptEngine.m_AppDomainManager.LoadScript(CompiledScriptFile); CompiledScript =
m_scriptEngine.m_AppDomainManager.LoadScript(
CompiledScriptFile, out id.AppDomain);
//#if DEBUG id.Script = CompiledScript;
//m_scriptEngine.Log.DebugFormat("[" + m_scriptEngine.ScriptEngineName + "]: Script " + itemID + " occupies {0} bytes", GC.GetTotalMemory(true) - before); id.Source = Script;
//#endif id.StartParam = startParam;
id.State = "default";
CompiledScript.Source = Script; id.Running = true;
CompiledScript.StartParam = startParam; id.Disabled = false;
// Add it to our script memstruct // Add it to our script memstruct
m_scriptEngine.m_ScriptManager.SetScript(localID, itemID, CompiledScript); m_scriptEngine.m_ScriptManager.SetScript(localID, itemID, id);
// We need to give (untrusted) assembly a private instance of BuiltIns
// this private copy will contain Read-Only FullitemID so that it can bring that on to the server whenever needed.
// OSSL_BuilIn_Commands LSLB = new OSSL_BuilIn_Commands(m_scriptEngine, m_host, localID, itemID);
LSL_Api LSL = new LSL_Api(); LSL_Api LSL = new LSL_Api();
OSSL_Api OSSL = new OSSL_Api(); OSSL_Api OSSL = new OSSL_Api();
LSL.Initialize(m_scriptEngine, m_host, localID, itemID); LSL.Initialize(m_scriptEngine, m_host, localID, itemID);
OSSL.Initialize(m_scriptEngine, m_host, localID, itemID); OSSL.Initialize(m_scriptEngine, m_host, localID, itemID);
// Start the script - giving it BuiltIns // Start the script - giving it the APIs
CompiledScript.InitApi("LSL", LSL); CompiledScript.InitApi("LSL", LSL);
CompiledScript.InitApi("OSSL", OSSL); CompiledScript.InitApi("OSSL", OSSL);
// Fire the first start-event // Fire the first start-event
int eventFlags = m_scriptEngine.m_ScriptManager.GetStateEventFlags(localID, itemID); int eventFlags =
m_scriptEngine.m_ScriptManager.GetStateEventFlags(
localID, itemID);
m_host.SetScriptEvents(itemID, eventFlags); m_host.SetScriptEvents(itemID, eventFlags);
m_scriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "state_entry", new DetectParams[0], new object[] { });
m_scriptEngine.m_EventQueueManager.AddToScriptQueue(
localID, itemID, "state_entry", new DetectParams[0],
new object[] { });
if (postOnRez) if (postOnRez)
{ {
m_scriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "on_rez", new DetectParams[0], new object[] { new LSL_Types.LSLInteger(startParam) }); m_scriptEngine.m_EventQueueManager.AddToScriptQueue(
localID, itemID, "on_rez", new DetectParams[0],
new object[] { new LSL_Types.LSLInteger(startParam) });
} }
} }
catch (Exception e) // LEGIT: User Scripting catch (Exception e) // LEGIT: User Scripting
{ {
//m_scriptEngine.Log.Error("[ScriptEngine]: Error compiling script: " + e.ToString());
try try
{ {
// DISPLAY ERROR INWORLD // DISPLAY ERROR INWORLD
string text = "Error compiling script:\r\n" + e.Message.ToString(); string text = "Error compiling script:\r\n" +
if (text.Length > 1500) e.Message.ToString();
text = text.Substring(0, 1499); // 0-1499 is 1500 characters if (text.Length > 1100)
World.SimChat(Utils.StringToBytes(text), ChatTypeEnum.DebugChannel, 2147483647, text = text.Substring(0, 1099);
m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
World.SimChat(Utils.StringToBytes(text),
ChatTypeEnum.DebugChannel, 2147483647,
m_host.AbsolutePosition, m_host.Name, m_host.UUID,
false);
} }
catch (Exception e2) // LEGIT: User Scripting catch (Exception e2) // LEGIT: User Scripting
{ {
m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Error displaying error in-world: " + e2.ToString()); m_scriptEngine.Log.Error("[" +
m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: " + m_scriptEngine.ScriptEngineName +
"Errormessage: Error compiling script:\r\n" + e.Message.ToString()); "]: Error displaying error in-world: " +
e2.ToString());
m_scriptEngine.Log.Error("[" +
m_scriptEngine.ScriptEngineName + "]: " +
"Errormessage: Error compiling script:\r\n" +
e2.Message.ToString());
} }
} }
} }
public void _StopScript(uint localID, UUID itemID) public void _StopScript(uint localID, UUID itemID)
{ {
IScript LSLBC = GetScript(localID, itemID); InstanceData id = GetScript(localID, itemID);
if (LSLBC == null) if (id == null)
return; return;
// Stop long command on script // Stop long command on script
AsyncCommandManager.RemoveScript(m_scriptEngine, localID, itemID); AsyncCommandManager.RemoveScript(m_scriptEngine, localID, itemID);
// TEMP: First serialize it
//GetSerializedScript(localID, itemID);
try try
{ {
// Get AppDomain // Get AppDomain
AppDomain ad = LSLBC.Exec.GetAppDomain();
// Tell script not to accept new requests // Tell script not to accept new requests
m_scriptEngine.m_ScriptManager.GetScript(localID, itemID).Exec.StopScript(); id.Running = false;
id.Disabled = true;
AppDomain ad = id.AppDomain;
// Remove from internal structure // Remove from internal structure
m_scriptEngine.m_ScriptManager.RemoveScript(localID, itemID); RemoveScript(localID, itemID);
// Tell AppDomain that we have stopped script // Tell AppDomain that we have stopped script
m_scriptEngine.m_AppDomainManager.StopScript(ad); m_scriptEngine.m_AppDomainManager.StopScript(ad);
} }
catch (Exception e) // LEGIT: User Scripting catch (Exception e) // LEGIT: User Scripting
{ {
m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception stopping script localID: " + localID + " LLUID: " + itemID.ToString() + m_scriptEngine.Log.Error("[" +
": " + e.ToString()); m_scriptEngine.ScriptEngineName +
"]: Exception stopping script localID: " +
localID + " LLUID: " + itemID.ToString() +
": " + e.ToString());
} }
} }
public void ReadConfig() public void ReadConfig()
{ {
// scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30);
// TODO: Requires sharing of all ScriptManagers to single thread // TODO: Requires sharing of all ScriptManagers to single thread
PrivateThread = true; // m_scriptEngine.ScriptConfigSource.GetBoolean("PrivateScriptLoadUnloadThread", false); PrivateThread = true;
LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt("LoadUnloadMaxQueueSize", 100); LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt(
"LoadUnloadMaxQueueSize", 100);
} }
#region Object init/shutdown #region Object init/shutdown
@ -263,17 +276,20 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
{ {
m_scriptEngine = scriptEngine; m_scriptEngine = scriptEngine;
} }
public void Setup() public void Setup()
{ {
ReadConfig(); ReadConfig();
Initialize(); Initialize();
} }
public void Start() public void Start()
{ {
m_started = true; m_started = true;
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); AppDomain.CurrentDomain.AssemblyResolve +=
new ResolveEventHandler(CurrentDomain_AssemblyResolve);
// //
// CREATE THREAD // CREATE THREAD
@ -289,43 +305,20 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
// Shared thread - make sure one exist, then assign it to the private // Shared thread - make sure one exist, then assign it to the private
if (staticScriptLoadUnloadThread == null) if (staticScriptLoadUnloadThread == null)
{ {
//staticScriptLoadUnloadThread = StartScriptLoadUnloadThread(); //staticScriptLoadUnloadThread =
// StartScriptLoadUnloadThread();
} }
scriptLoadUnloadThread = staticScriptLoadUnloadThread; scriptLoadUnloadThread = staticScriptLoadUnloadThread;
} }
} }
// TODO: unused
// private static int privateThreadCount = 0;
// private Thread StartScriptLoadUnloadThread()
// {
// Thread t = new Thread(ScriptLoadUnloadThreadLoop);
// string name = "ScriptLoadUnloadThread:";
// if (PrivateThread)
// {
// name += "Private:" + privateThreadCount;
// privateThreadCount++;
// }
// else
// {
// name += "Shared";
// }
// t.Name = name;
// t.IsBackground = true;
// t.Priority = ThreadPriority.Normal;
// t.Start();
// OpenSim.Framework.ThreadTracker.Add(t);
// return t;
// }
~ScriptManager() ~ScriptManager()
{ {
// Abort load/unload thread // Abort load/unload thread
try try
{ {
//PleaseShutdown = true; if (scriptLoadUnloadThread != null &&
//Thread.Sleep(100); scriptLoadUnloadThread.IsAlive == true)
if (scriptLoadUnloadThread != null && scriptLoadUnloadThread.IsAlive == true)
{ {
scriptLoadUnloadThread.Abort(); scriptLoadUnloadThread.Abort();
//scriptLoadUnloadThread.Join(); //scriptLoadUnloadThread.Join();
@ -340,28 +333,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
#region Load / Unload scripts (Thread loop) #region Load / Unload scripts (Thread loop)
// TODO: unused
// private void ScriptLoadUnloadThreadLoop()
// {
// try
// {
// while (true)
// {
// if (LUQueue.Count == 0)
// Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
// //if (PleaseShutdown)
// // return;
// DoScriptLoadUnload();
// }
// }
// catch (ThreadAbortException tae)
// {
// string a = tae.ToString();
// a = String.Empty;
// // Expected
// }
// }
public void DoScriptLoadUnload() public void DoScriptLoadUnload()
{ {
if (!m_started) if (!m_started)
@ -371,7 +342,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
{ {
if (LUQueue.Count > 0) if (LUQueue.Count > 0)
{ {
m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngineName); m_scriptEngine.Log.InfoFormat("[{0}]: Loading script",
m_scriptEngine.ScriptEngineName);
LUStruct item = LUQueue.Dequeue(); LUStruct item = LUQueue.Dequeue();
if (item.Action == LUType.Unload) if (item.Action == LUType.Unload)
@ -381,7 +353,8 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngi
} }
else if (item.Action == LUType.Load) else if (item.Action == LUType.Load)
{ {
_StartScript(item.localID, item.itemID, item.script, item.startParam, item.postOnRez); _StartScript(item.localID, item.itemID, item.script,
item.startParam, item.postOnRez);
} }
} }
} }
@ -391,20 +364,17 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngi
#region Helper functions #region Helper functions
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) private static Assembly CurrentDomain_AssemblyResolve(
object sender, ResolveEventArgs args)
{ {
//Console.WriteLine("ScriptManager.CurrentDomain_AssemblyResolve: " + args.Name); return Assembly.GetExecutingAssembly().FullName == args.Name ?
return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null; Assembly.GetExecutingAssembly() : null;
} }
#endregion #endregion
#region Start/Stop/Reset script #region Start/Stop/Reset script
// private readonly Object startStopLock = new Object();
/// <summary> /// <summary>
/// Fetches, loads and hooks up a script to an objects events /// Fetches, loads and hooks up a script to an objects events
/// </summary> /// </summary>
@ -416,7 +386,13 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngi
{ {
if ((LUQueue.Count >= LoadUnloadMaxQueueSize) && m_started) if ((LUQueue.Count >= LoadUnloadMaxQueueSize) && m_started)
{ {
m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: ERROR: Load/unload queue item count is at " + LUQueue.Count + ". Config variable \"LoadUnloadMaxQueueSize\" is set to " + LoadUnloadMaxQueueSize + ", so ignoring new script."); m_scriptEngine.Log.Error("[" +
m_scriptEngine.ScriptEngineName +
"]: ERROR: Load/unload queue item count is at " +
LUQueue.Count +
". Config variable \"LoadUnloadMaxQueueSize\" "+
"is set to " + LoadUnloadMaxQueueSize +
", so ignoring new script.");
return; return;
} }
@ -428,7 +404,6 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngi
ls.startParam = startParam; ls.startParam = startParam;
ls.postOnRez = postOnRez; ls.postOnRez = postOnRez;
LUQueue.Enqueue(ls); LUQueue.Enqueue(ls);
m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.ScriptEngineName);
} }
} }
@ -451,10 +426,6 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
} }
} }
// Create a new instance of the compiler (reuse)
//private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler();
#endregion #endregion
#region Perform event execution in script #region Perform event execution in script
@ -466,33 +437,23 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
/// <param name="itemID">Script ID</param> /// <param name="itemID">Script ID</param>
/// <param name="FunctionName">Name of function</param> /// <param name="FunctionName">Name of function</param>
/// <param name="args">Arguments to pass to function</param> /// <param name="args">Arguments to pass to function</param>
internal void ExecuteEvent(uint localID, UUID itemID, string FunctionName, DetectParams[] qParams, object[] args) internal void ExecuteEvent(uint localID, UUID itemID,
string FunctionName, DetectParams[] qParams, object[] args)
{ {
//cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined InstanceData id = GetScript(localID, itemID);
///#if DEBUG if (id == null)
/// Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
///#endif
// Execute a function in the script
//m_scriptEngine.Log.Info("[" + ScriptEngineName + "]: Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
//ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
IScript Script = GetScript(localID, itemID);
if (Script == null)
{
return; return;
}
//cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined detparms[id] = qParams;
///#if DEBUG if (id.Running)
/// Console.WriteLine("ScriptEngine: Executing event: " + FunctionName); id.Script.Exec.ExecuteEvent(id.State, FunctionName, args);
///#endif detparms.Remove(id);
// Must be done in correct AppDomain, so leaving it up to the script itself
detparms[Script] = qParams;
Script.Exec.ExecuteEvent(FunctionName, args);
detparms.Remove(Script);
} }
public uint GetLocalID(UUID itemID) public uint GetLocalID(UUID itemID)
{ {
foreach (KeyValuePair<uint, Dictionary<UUID, IScript> > k in Scripts) foreach (KeyValuePair<uint, Dictionary<UUID, InstanceData> > k
in Scripts)
{ {
if (k.Value.ContainsKey(itemID)) if (k.Value.ContainsKey(itemID))
return k.Key; return k.Key;
@ -502,15 +463,15 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
public int GetStateEventFlags(uint localID, UUID itemID) public int GetStateEventFlags(uint localID, UUID itemID)
{ {
// Console.WriteLine("GetStateEventFlags for <" + localID + "," + itemID + ">");
try try
{ {
IScript Script = GetScript(localID, itemID); InstanceData id = GetScript(localID, itemID);
if (Script == null) if (id == null)
{ {
return 0; return 0;
} }
ExecutorBase.scriptEvents evflags = Script.Exec.GetStateEventFlags(); ExecutorBase.scriptEvents evflags =
id.Script.Exec.GetStateEventFlags(id.State);
return (int)evflags; return (int)evflags;
} }
catch (Exception) catch (Exception)
@ -530,50 +491,50 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
if (Scripts.ContainsKey(localID) == false) if (Scripts.ContainsKey(localID) == false)
return new List<UUID>(); return new List<UUID>();
Dictionary<UUID, IScript> Obj; Dictionary<UUID, InstanceData> Obj;
Scripts.TryGetValue(localID, out Obj); Scripts.TryGetValue(localID, out Obj);
return new List<UUID>(Obj.Keys); return new List<UUID>(Obj.Keys);
} }
public IScript GetScript(uint localID, UUID itemID) public InstanceData GetScript(uint localID, UUID itemID)
{ {
lock (scriptLock) lock (scriptLock)
{ {
IScript Script = null; InstanceData id = null;
if (Scripts.ContainsKey(localID) == false) if (Scripts.ContainsKey(localID) == false)
return null; return null;
Dictionary<UUID, IScript> Obj; Dictionary<UUID, InstanceData> Obj;
Scripts.TryGetValue(localID, out Obj); Scripts.TryGetValue(localID, out Obj);
if (Obj.ContainsKey(itemID) == false) if (Obj.ContainsKey(itemID) == false)
return null; return null;
// Get script // Get script
Obj.TryGetValue(itemID, out Script); Obj.TryGetValue(itemID, out id);
return Script; return id;
} }
} }
public void SetScript(uint localID, UUID itemID, IScript Script) public void SetScript(uint localID, UUID itemID, InstanceData id)
{ {
lock (scriptLock) lock (scriptLock)
{ {
// Create object if it doesn't exist // Create object if it doesn't exist
if (Scripts.ContainsKey(localID) == false) if (Scripts.ContainsKey(localID) == false)
{ {
Scripts.Add(localID, new Dictionary<UUID, IScript>()); Scripts.Add(localID, new Dictionary<UUID, InstanceData>());
} }
// Delete script if it exists // Delete script if it exists
Dictionary<UUID, IScript> Obj; Dictionary<UUID, InstanceData> Obj;
Scripts.TryGetValue(localID, out Obj); Scripts.TryGetValue(localID, out Obj);
if (Obj.ContainsKey(itemID) == true) if (Obj.ContainsKey(itemID) == true)
Obj.Remove(itemID); Obj.Remove(itemID);
// Add to object // Add to object
Obj.Add(itemID, Script); Obj.Add(itemID, id);
} }
} }
@ -587,7 +548,7 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
return; return;
// Delete script if it exists // Delete script if it exists
Dictionary<UUID, IScript> Obj; Dictionary<UUID, InstanceData> Obj;
Scripts.TryGetValue(localID, out Obj); Scripts.TryGetValue(localID, out Obj);
if (Obj.ContainsKey(itemID) == true) if (Obj.ContainsKey(itemID) == true)
Obj.Remove(itemID); Obj.Remove(itemID);
@ -598,13 +559,13 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
public void ResetScript(uint localID, UUID itemID) public void ResetScript(uint localID, UUID itemID)
{ {
IScript s = GetScript(localID, itemID); InstanceData id = GetScript(localID, itemID);
string script = s.Source; string script = id.Source;
StopScript(localID, itemID); StopScript(localID, itemID);
SceneObjectPart part = World.GetSceneObjectPart(localID); SceneObjectPart part = World.GetSceneObjectPart(localID);
part.GetInventoryItem(itemID).PermsMask = 0; part.GetInventoryItem(itemID).PermsMask = 0;
part.GetInventoryItem(itemID).PermsGranter = UUID.Zero; part.GetInventoryItem(itemID).PermsGranter = UUID.Zero;
StartScript(localID, itemID, script, s.StartParam, false); StartScript(localID, itemID, script, id.StartParam, false);
} }
@ -629,20 +590,10 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
#endregion #endregion
///// <summary> public DetectParams[] GetDetectParams(InstanceData id)
///// If set to true then threads and stuff should try to make a graceful exit
///// </summary>
//public bool PleaseShutdown
//{
// get { return _PleaseShutdown; }
// set { _PleaseShutdown = value; }
//}
//private bool _PleaseShutdown = false;
public DetectParams[] GetDetectParams(IScript script)
{ {
if (detparms.ContainsKey(script)) if (detparms.ContainsKey(id))
return detparms[script]; return detparms[id];
return null; return null;
} }