public void SaveState(string assembly) { // If we're currently in an event, just tell it to save upon return // if (m_InEvent) { m_SaveState = true; return; } PluginData = AsyncCommandManager.GetSerializationData(m_Engine, m_ItemID); string xml = ScriptSerializer.Serialize(this); if (m_CurrentState != xml) { try { FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state")); System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); Byte[] buf = enc.GetBytes(xml); fs.Write(buf, 0, buf.Length); fs.Close(); } catch (Exception e) { m_log.Error("Unable to save xml\n" + e.ToString()); } //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state"))) //{ // throw new Exception("Completed persistence save, but no file was created"); //} m_CurrentState = xml; } }
public string GetXMLState() { bool run = Running; Stop(100); Running = run; // We should not be doing this, but since we are about to // dispose this, it really doesn't make a difference // This is meant to work around a Windows only race // m_InEvent = false; // Force an update of the in-memory plugin data // PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID); return(ScriptSerializer.Serialize(this)); }
public void SaveState(string assembly) { // If we're currently in an event, just tell it to save upon return // if (m_InEvent) { m_SaveState = true; return; } PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID); string xml = ScriptSerializer.Serialize(this); // Compare hash of the state we just just created with the state last written to disk // If the state is different, update the disk file. UUID hash = UUID.Parse(Utils.MD5String(xml)); if (hash != m_CurrentStateHash) { try { FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")); System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); Byte[] buf = enc.GetBytes(xml); fs.Write(buf, 0, buf.Length); fs.Close(); } catch (Exception) { // m_log.Error("Unable to save xml\n"+e.ToString()); } //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state"))) //{ // throw new Exception("Completed persistence save, but no file was created"); //} m_CurrentStateHash = hash; } }
public ScriptInstance(IScriptEngine engine, SceneObjectPart part, UUID itemID, UUID assetID, string assembly, AppDomain dom, string primName, string scriptName, int startParam, bool postOnRez, StateSource stateSource, int maxScriptQueue) { State = "default"; EventQueue = new Queue(32); Engine = engine; LocalID = part.LocalId; ObjectID = part.UUID; RootLocalID = part.ParentGroup.LocalId; RootObjectID = part.ParentGroup.UUID; ItemID = itemID; AssetID = assetID; PrimName = primName; ScriptName = scriptName; m_Assembly = assembly; StartParam = startParam; m_MaxScriptQueue = maxScriptQueue; m_stateSource = stateSource; m_postOnRez = postOnRez; m_AttachedAvatar = part.ParentGroup.AttachedAvatar; m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID; if (part != null) { lock (part.TaskInventory) { if (part.TaskInventory.ContainsKey(ItemID)) { ScriptTask = part.TaskInventory[ItemID]; } } } ApiManager am = new ApiManager(); foreach (string api in am.GetApis()) { m_Apis[api] = am.CreateApi(api); m_Apis[api].Initialize(engine, part, LocalID, itemID); } try { if (dom != System.AppDomain.CurrentDomain) { m_Script = (IScript)dom.CreateInstanceAndUnwrap( Path.GetFileNameWithoutExtension(assembly), "SecondLife.Script"); } else { m_Script = (IScript)Assembly.Load( Path.GetFileNameWithoutExtension(assembly)).CreateInstance( "SecondLife.Script"); } //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); // lease.Register(this); } catch (Exception e) { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Error loading assembly {0}. Exception {1}{2}", assembly, e.Message, e.StackTrace); } try { foreach (KeyValuePair <string, IScriptApi> kv in m_Apis) { m_Script.InitApi(kv.Key, kv.Value); } // // m_log.Debug("[Script] Script instance created"); part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); } catch (Exception e) { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Error loading script instance from assembly {0}. Exception {1}{2}", assembly, e.Message, e.StackTrace); return; } m_SaveState = true; string savedState = Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state"); if (File.Exists(savedState)) { string xml = String.Empty; try { FileInfo fi = new FileInfo(savedState); int size = (int)fi.Length; if (size < 512000) { using (FileStream fs = File.Open(savedState, FileMode.Open, FileAccess.Read, FileShare.None)) { System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); Byte[] data = new Byte[size]; fs.Read(data, 0, size); xml = enc.GetString(data); ScriptSerializer.Deserialize(xml, this); AsyncCommandManager.CreateFromData(Engine, LocalID, ItemID, ObjectID, PluginData); // m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); Running = false; if (ShuttingDown) { m_startOnInit = false; } // we get new rez events on sim restart, too // but if there is state, then we fire the change // event // We loaded state, don't force a re-save m_SaveState = false; m_startedFromSavedState = true; } } else { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Unable to load script state from assembly {0}: Memory limit exceeded", assembly); } } catch (Exception e) { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Unable to load script state from assembly {0}. XML is {1}. Exception {2}{3}", assembly, xml, e.Message, e.StackTrace); } } // else // { // ScenePresence presence = Engine.World.GetScenePresence(part.OwnerID); // if (presence != null && (!postOnRez)) // presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); // } }
/// <summary> /// Load the script from an assembly into an AppDomain. /// </summary> /// <param name='dom'></param> /// <param name='assembly'></param> /// <param name='stateSource'></param> /// <returns>false if load failed, true if suceeded</returns> public bool Load(AppDomain dom, string assembly, StateSource stateSource) { m_Assembly = assembly; m_stateSource = stateSource; ApiManager am = new ApiManager(); foreach (string api in am.GetApis()) { m_Apis[api] = am.CreateApi(api); m_Apis[api].Initialize(Engine, Part, ScriptTask, m_coopSleepHandle); } try { object[] constructorParams; Assembly scriptAssembly = dom.Load(Path.GetFileNameWithoutExtension(assembly)); Type scriptType = scriptAssembly.GetType("SecondLife.XEngineScript"); if (scriptType != null) { constructorParams = new object[] { m_coopSleepHandle }; } else { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. You must remove all existing {6}* script DLL files before using enabling co-op termination" + ", either by setting DeleteScriptsOnStartup = true in [XEngine] for one run" + " or by deleting these files manually.", ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly); return(false); } // m_log.DebugFormat( // "[SCRIPT INSTANCE]: Looking to load {0} from assembly {1} in {2}", // scriptType.FullName, Path.GetFileNameWithoutExtension(assembly), Engine.World.Name); if (dom != System.AppDomain.CurrentDomain) { m_Script = (IScript)dom.CreateInstanceAndUnwrap( Path.GetFileNameWithoutExtension(assembly), scriptType.FullName, false, BindingFlags.Default, null, constructorParams, null, null); } else { m_Script = (IScript)scriptAssembly.CreateInstance( scriptType.FullName, false, BindingFlags.Default, null, constructorParams, null, null); } //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); // lease.Register(this); } catch (Exception e) { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error loading assembly {6}. Exception {7}{8}", ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly, e.Message, e.StackTrace); return(false); } try { foreach (KeyValuePair <string, IScriptApi> kv in m_Apis) { m_Script.InitApi(kv.Key, kv.Value); } // // m_log.Debug("[Script] Script instance created"); Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); } catch (Exception e) { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error initializing script instance. Exception {6}{7}", ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, e.Message, e.StackTrace); return(false); } m_SaveState = true; string savedState = Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state"); if (File.Exists(savedState)) { string xml = String.Empty; try { FileInfo fi = new FileInfo(savedState); int size = (int)fi.Length; if (size < 512000) { using (FileStream fs = File.Open(savedState, FileMode.Open, FileAccess.Read, FileShare.None)) { Byte[] data = new Byte[size]; fs.Read(data, 0, size); xml = Encoding.UTF8.GetString(data); ScriptSerializer.Deserialize(xml, this); AsyncCommandManager.CreateFromData(Engine, LocalID, ItemID, ObjectID, PluginData); // m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); if (!Running) { m_startOnInit = false; } Running = false; // we get new rez events on sim restart, too // but if there is state, then we fire the change // event // We loaded state, don't force a re-save m_SaveState = false; m_startedFromSavedState = true; } } else { m_log.WarnFormat( "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.", ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState); } } catch (Exception e) { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}", ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace); } } // else // { // ScenePresence presence = Engine.World.GetScenePresence(part.OwnerID); // if (presence != null && (!postOnRez)) // presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); // } return(true); }
/// <summary> /// Load the script from an assembly into an AppDomain. /// </summary> /// <param name='dom'></param> /// <param name='assembly'></param> /// <param name='dataPath'> /// Path for all script associated data (state, etc.). In a multi-region set up /// with all scripts loading into the same AppDomain this may not be the same place as the DLL itself. /// </param> /// <param name='stateSource'></param> /// <returns>false if load failed, true if suceeded</returns> public bool Load( IScript script, EventWaitHandle coopSleepHandle, string assemblyPath, string dataPath, StateSource stateSource, bool coopTermination) { m_Script = script; m_coopSleepHandle = coopSleepHandle; m_assemblyPath = assemblyPath; m_dataPath = dataPath; m_stateSource = stateSource; m_coopTermination = coopTermination; ApiManager am = new ApiManager(); foreach (string api in am.GetApis()) { m_Apis[api] = am.CreateApi(api); m_Apis[api].Initialize(Engine, Part, ScriptTask, m_coopSleepHandle); } try { foreach (KeyValuePair <string, IScriptApi> kv in m_Apis) { m_Script.InitApi(kv.Key, kv.Value); } // // m_log.Debug("[Script] Script instance created"); Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); } catch (Exception e) { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error initializing script instance. Exception {6}{7}", ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, e.Message, e.StackTrace); return(false); } // For attachments, XEngine saves the state into a .state file when XEngine.SetXMLState() is called. string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state"); if (File.Exists(savedState)) { // m_log.DebugFormat( // "[SCRIPT INSTANCE]: Found state for script {0} for {1} ({2}) at {3} in {4}", // ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name); string xml = String.Empty; try { FileInfo fi = new FileInfo(savedState); int size = (int)fi.Length; if (size < 512000) { using (FileStream fs = File.Open(savedState, FileMode.Open, FileAccess.Read, FileShare.None)) { Byte[] data = new Byte[size]; fs.Read(data, 0, size); xml = Encoding.UTF8.GetString(data); ScriptSerializer.Deserialize(xml, this); AsyncCommandManager.CreateFromData(Engine, LocalID, ItemID, ObjectID, PluginData); // m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); if (!Running) { m_startOnInit = false; } Running = false; // we get new rez events on sim restart, too // but if there is state, then we fire the change // event // We loaded state, don't force a re-save m_SaveState = false; m_startedFromSavedState = true; } // If this script is in an attachment then we no longer need the state file. if (!StatePersistedHere) { RemoveState(); } } // else // { // m_log.WarnFormat( // "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.", // ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState); // } } catch (Exception e) { m_log.ErrorFormat( "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}", ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace); } } // else // { // m_log.DebugFormat( // "[SCRIPT INSTANCE]: Did not find state for script {0} for {1} ({2}) at {3} in {4}", // ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name); // } return(true); }
public void SaveState() { if (!Running) { return; } // We cannot call this inside the EventQueue lock since it will currently take AsyncCommandManager.staticLock. // This may already be held by AsyncCommandManager.DoOneCmdHandlerPass() which in turn can take EventQueue // lock via ScriptInstance.PostEvent(). PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID); // We need to lock here to avoid any race with a thread that is removing this script. lock (EventQueue) { // Check again to avoid a race with a thread in Stop() if (!Running) { return; } // If we're currently in an event, just tell it to save upon return // if (m_InEvent) { m_SaveState = true; return; } // m_log.DebugFormat( // "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}", // ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name); string xml = ScriptSerializer.Serialize(this); // Compare hash of the state we just just created with the state last written to disk // If the state is different, update the disk file. UUID hash = UUID.Parse(Utils.MD5String(xml)); if (hash != m_CurrentStateHash) { try { using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() + ".state"))) { Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml); fs.Write(buf, 0, buf.Length); } } catch (Exception) { // m_log.Error("Unable to save xml\n"+e.ToString()); } //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state"))) //{ // throw new Exception("Completed persistence save, but no file was created"); //} m_CurrentStateHash = hash; } } }
public ScriptInstance(IScriptEngine engine, SceneObjectPart part, UUID itemID, UUID assetID, string assembly, AppDomain dom, string primName, string scriptName, int startParam, bool postOnRez, StateSource stateSource, int maxScriptQueue) { m_Engine = engine; m_LocalID = part.LocalId; m_ObjectID = part.UUID; m_ItemID = itemID; m_AssetID = assetID; m_PrimName = primName; m_ScriptName = scriptName; m_Assembly = assembly; m_StartParam = startParam; m_MaxScriptQueue = maxScriptQueue; m_stateSource = stateSource; m_postOnRez = postOnRez; m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID; if (part != null) { lock (part.TaskInventory) { if (part.TaskInventory.ContainsKey(m_ItemID)) { m_thisScriptTask = part.TaskInventory[m_ItemID]; } } } ApiManager am = new ApiManager(); foreach (string api in am.GetApis()) { m_Apis[api] = am.CreateApi(api); m_Apis[api].Initialize(engine, part, m_LocalID, itemID); } try { m_Script = (IScript)dom.CreateInstanceAndUnwrap( Path.GetFileNameWithoutExtension(assembly), "SecondLife.Script"); // Add a sponsor to the script // ISponsor scriptSponsor = new ScriptSponsor(); // ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as MarshalByRefObject); // lease.Register(scriptSponsor); //m_ScriptSponsor = scriptSponsor; } catch (Exception e) { m_log.ErrorFormat("[Script] Error loading assembly {0}\n" + e.ToString(), assembly); } try { foreach (KeyValuePair <string, IScriptApi> kv in m_Apis) { m_Script.InitApi(kv.Key, kv.Value); } // m_log.Debug("[Script] Script instance created"); part.SetScriptEvents(m_ItemID, (int)m_Script.GetStateEventFlags(State)); } catch (Exception e) { m_log.Error("[Script] Error loading script instance\n" + e.ToString()); return; } m_SaveState = true; string savedState = Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state"); if (File.Exists(savedState)) { string xml = String.Empty; try { FileInfo fi = new FileInfo(savedState); int size = (int)fi.Length; if (size < 512000) { using (FileStream fs = File.Open(savedState, FileMode.Open, FileAccess.Read, FileShare.None)) { System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); Byte[] data = new Byte[size]; fs.Read(data, 0, size); xml = enc.GetString(data); ScriptSerializer.Deserialize(xml, this); AsyncCommandManager.CreateFromData(m_Engine, m_LocalID, m_ItemID, m_ObjectID, PluginData); // m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", m_PrimName, m_ScriptName); part.SetScriptEvents(m_ItemID, (int)m_Script.GetStateEventFlags(State)); if (m_RunEvents && (!m_ShuttingDown)) { m_RunEvents = false; } else { m_RunEvents = false; m_startOnInit = false; } // we get new rez events on sim restart, too // but if there is state, then we fire the change // event // We loaded state, don't force a re-save m_SaveState = false; m_startedFromSavedState = true; } } else { m_log.Error("[Script] Unable to load script state: Memory limit exceeded"); } } catch (Exception e) { m_log.ErrorFormat("[Script] Unable to load script state from xml: {0}\n" + e.ToString(), xml); } } else { ScenePresence presence = m_Engine.World.GetScenePresence(part.OwnerID); if (presence != null && (!postOnRez)) { presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); } // m_log.ErrorFormat("[Script] Unable to load script state, file not found"); } }