public void StartScripts(LUStruct[] items) { List<LUStruct> NeedsFired = new List<LUStruct>(); foreach (LUStruct item in items) { if (m_ScriptEngine.ConsoleDisabled || m_ScriptEngine.Disabled || m_ScriptEngine.Scene == null || !m_ScriptEngine.Scene.ShouldRunHeartbeat) break; if (item.Action == LUType.Unload) { //Close item.ID.CloseAndDispose(true); } else if (item.Action == LUType.Load || item.Action == LUType.Reupload) { try { //Start if (item.ID.Start(item)) NeedsFired.Add(item); } catch (Exception ex) { MainConsole.Instance.Error("[" + m_ScriptEngine.ScriptEngineName + "]: LEAKED COMPILE ERROR: " + ex); } } } foreach (LUStruct item in NeedsFired) { //Fire the events afterward so that they all start at the same time item.ID.FireEvents(); } }
/// <summary> /// This starts the script and sets up the variables. /// </summary> /// <returns></returns> public bool Start(LUStruct startInfo) { bool reupload = startInfo.Action == LUType.Reupload; DateTime StartTime = DateTime.Now.ToUniversalTime(); Running = true; Suspended = false; //Clear out the removing of events for this script. IgnoreNew = false; Interlocked.Increment(ref VersionID); //Reset this StartedFromSavedState = false; //Clear out previous errors if they were not cleaned up m_ScriptEngine.ScriptErrorReporter.RemoveError(ItemID); //Find the inventory item Part.TaskInventory.TryGetValue(ItemID, out InventoryItem); if (InventoryItem == null) { MainConsole.Instance.Warn("[VS]: Could not find inventory item for script " + ItemID + ", part" + Part.Name + "@" + Part.AbsolutePosition); return false; } //Try to see if this was rezzed from someone's inventory UserInventoryItemID = Part.FromUserInventoryItemID; //Try to find the avatar who started this. IScenePresence presence = World.GetScenePresence(Part.OwnerID); if (startInfo.ClearStateSaves) m_ScriptEngine.StateSave.DeleteFrom(this); //Now that the initial loading is complete, // we need to find the state save and start loading the info from it StateSave LastStateSave = m_ScriptEngine.StateSave.FindScriptStateSave(this); if (!reupload && Loading && LastStateSave != null) { //Deserialize the most important pieces first Source = LastStateSave.Source; } if (string.IsNullOrEmpty(Source)) { byte[] asset = Part.ParentEntity.Scene.AssetService.GetData(InventoryItem.AssetID.ToString()); if (null == asset) { MainConsole.Instance.ErrorFormat( "[ScriptData]: " + "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", InventoryItem.Name, InventoryItem.ItemID, Part.AbsolutePosition, Part.ParentEntity.Scene.RegionInfo.RegionName, InventoryItem.AssetID); ScriptEngine.ScriptProtection.RemoveScript(this); return false; } Source = Utils.BytesToString(asset); } if (string.IsNullOrEmpty(Source)) { MainConsole.Instance.ErrorFormat( "[ScriptData]: " + "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", InventoryItem.Name, InventoryItem.ItemID, Part.AbsolutePosition, Part.ParentEntity.Scene.RegionInfo.RegionName, InventoryItem.AssetID); ScriptEngine.ScriptProtection.RemoveScript(this); return false; } #region HTML Reader if (ScriptEngine.ScriptProtection.AllowHTMLLinking) { //Read the URL and load it. if (Source.Contains("#IncludeHTML ")) { string URL = ""; int line = Source.IndexOf("#IncludeHTML "); URL = Source.Remove(0, line); URL = URL.Replace("#IncludeHTML ", ""); URL = URL.Split('\n')[0]; string webSite = Utilities.ReadExternalWebsite(URL); Source = Source.Replace("#IncludeHTML " + URL, webSite); } } else { //Remove the line then if (Source.Contains("#IncludeHTML ")) { string URL = ""; int line = Source.IndexOf("#IncludeHTML "); URL = Source.Remove(0, line); URL = URL.Replace("#IncludeHTML ", ""); URL = URL.Split('\n')[0]; Source = Source.Replace("#IncludeHTML " + URL, ""); } } #endregion //Find the default state save DefaultState = m_ScriptEngine.Compiler.FindDefaultStateForScript(Source); State = DefaultState; //If the saved state exists, if it isn't a reupload (something changed), and if the assembly exists, load the state save if (!reupload && Loading && LastStateSave != null && File.Exists(LastStateSave.AssemblyName)) { //Retrive the previous assembly AssemblyName = LastStateSave.AssemblyName; } else { Compiled = false; //if (!reupload && Loading && LastStateSave != null && !LastStateSave.Compiled) // return false;//If we're trying to start up and we failed before, just give up if (reupload) { LastStateSave = null; //Close the previous script CloseAndDispose(false); //We don't want to back it up Interlocked.Increment(ref VersionID); m_ScriptEngine.MaintenanceThread.SetEventSchSetIgnoreNew(this, false); // accept new events } //Try to find a previously compiled script in this instance string PreviouslyCompiledAssemblyName = ScriptEngine.ScriptProtection.TryGetPreviouslyCompiledScript(Source); if (PreviouslyCompiledAssemblyName != null) //Already exists in this instance, so we do not need to check whether it exists AssemblyName = PreviouslyCompiledAssemblyName; else { try { m_ScriptEngine.Compiler.PerformScriptCompile(Source, Part.OwnerID, out AssemblyName); #region Errors and Warnings #region Errors string[] compileerrors = m_ScriptEngine.Compiler.GetErrors(); if (compileerrors.Length != 0) { string error = string.Empty; foreach (string compileerror in compileerrors) { error += compileerror; } DisplayUserNotification(error, "compiling", reupload, true); //It might have failed, but we still need to add it so that we can reuse this script data class later ScriptEngine.ScriptProtection.AddNewScript(this); m_ScriptEngine.StateSave.SaveStateTo(this, true); return false; } #endregion #region Warnings if (m_ScriptEngine.ShowWarnings) { string[] compilewarnings = m_ScriptEngine.Compiler.GetWarnings(); if (compilewarnings != null && compilewarnings.Length != 0) { string error = string.Empty; foreach (string compileerror in compilewarnings) { error += compileerror; } DisplayUserNotification(error, "compiling", reupload, false); //It might have failed, but we still need to add it so that we can reuse this script data class later ScriptEngine.ScriptProtection.AddNewScript(this); return false; } } #endregion #endregion } catch (Exception ex) { //LEAVE IT AS ToString() SO THAT WE GET THE STACK TRACE TOO DisplayUserNotification(ex.ToString(), "(exception) compiling", reupload, true); //It might have failed, but we still need to add it so that we can reuse this script data class later ScriptEngine.ScriptProtection.AddNewScript(this); return false; } } } bool useDebug = false; if (useDebug) MainConsole.Instance.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Stage 1 compile: " + (DateTime.Now.ToUniversalTime() - StartTime).TotalSeconds); //Create the app domain if needed. try { Script = m_ScriptEngine.AppDomainManager.LoadScript(AssemblyName, "Script.ScriptClass", out AppDomain); m_ScriptEngine.Compiler.FinishCompile(this, Script); //Add now so that we don't add it too early and give it the possibility to fail ScriptEngine.ScriptProtection.AddPreviouslyCompiled(Source, this); } catch (FileNotFoundException) // Not valid!!! { MainConsole.Instance.Error("[" + m_ScriptEngine.ScriptEngineName + "]: File not found in app domain creation. Corrupt state save! " + AssemblyName); ScriptEngine.ScriptProtection.RemovePreviouslyCompiled(Source); return Start(startInfo); // Lets restart the script if this happens } catch (Exception ex) { DisplayUserNotification(ex.ToString(), "app domain creation", reupload, true); //It might have failed, but we still need to add it so that we can reuse this script data class later ScriptEngine.ScriptProtection.AddNewScript(this); return false; } Compiled = true; //We compiled successfully //ILease lease = (ILease)RemotingServices.GetLifetimeService(Script as MarshalByRefObject); //if (lease != null) //Its null if it is all running in the same app domain // lease.Register(Script.Sponsor); //If its a reupload, an avatar is waiting for the script errors if (reupload) m_ScriptEngine.ScriptErrorReporter.AddError(ItemID, new ArrayList(new[] {"SUCCESSFULL"})); if (useDebug) MainConsole.Instance.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Stage 2 compile: " + (DateTime.Now.ToUniversalTime() - StartTime).TotalSeconds); SetApis(); //Now do the full state save finding now that we have an app domain. if (LastStateSave != null) { string assy = AssemblyName; // don't restore the assembly name, the one we have is right (if re-compiled or not) m_ScriptEngine.StateSave.Deserialize(this, LastStateSave); AssemblyName = assy; if (string.IsNullOrEmpty(this.State) && DefaultState != this.State) //Sometimes, "" is a valid state for other script languages { MainConsole.Instance.Warn("Resetting broken script save state\n" + " : "+InventoryItem.Name+":"+this.Part.Name + " @ " +Part.AbsolutePosition + "\n in region " + Part.ParentEntity.Scene.RegionInfo.RegionName); this.State = DefaultState; m_ScriptEngine.StateSave.DeleteFrom(Part, LastStateSave.ItemID); m_ScriptEngine.StateSave.SaveStateTo(this, true); } else { // we get new rez events on sim restart, too // but if there is state, then we fire the change // event StartedFromSavedState = true; } // ItemID changes sometimes (not sure why, but observed it) // If so we want to clear out the old save state, // which would otherwise have hung around in the object forever if (LastStateSave.ItemID != ItemID) { m_ScriptEngine.StateSave.DeleteFrom(Part, LastStateSave.ItemID); m_ScriptEngine.StateSave.SaveStateTo(this, true); } } else { //Make a new state save now m_ScriptEngine.StateSave.SaveStateTo(this, true); } //Set the event flags Part.SetScriptEvents(ItemID, Script.GetStateEventFlags(State)); // Add it to our script memstruct so it can be found by other scripts ScriptEngine.ScriptProtection.AddNewScript(this); //All done, compiled successfully Loading = false; if (MainConsole.Instance.IsDebugEnabled) { TimeSpan time = (DateTime.Now.ToUniversalTime() - StartTime); MainConsole.Instance.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Started Script " + InventoryItem.Name + " in object " + Part.Name + "@" + Part.ParentEntity.RootChild.AbsolutePosition + (presence != null ? " by " + presence.Name : "") + " in region " + Part.ParentEntity.Scene.RegionInfo.RegionName + " in " + time.TotalSeconds + " seconds."); } return true; }
public void AddScriptChange(LUStruct[] items, LoadPriority priority) { if (RunInMainProcessingThread) StartScripts(items); else { LUQueue.Add(items, priority); if (!ScriptChangeIsRunning) StartThread("Change"); } }
/// <summary> /// This starts the script and sets up the variables. /// </summary> /// <returns></returns> public bool Start(LUStruct startInfo) { bool reupload = startInfo.Action == LUType.Reupload; DateTime StartTime = DateTime.Now.ToUniversalTime(); Running = true; Suspended = false; //Clear out the removing of events for this script. IgnoreNew = false; Interlocked.Increment(ref VersionID); //Reset this StartedFromSavedState = false; //Clear out previous errors if they were not cleaned up m_ScriptEngine.ScriptErrorReporter.RemoveError(ItemID); //Find the inventory item Part.TaskInventory.TryGetValue(ItemID, out InventoryItem); if (InventoryItem == null) { MainConsole.Instance.Warn("[Virtual Script Engine]: Could not find inventory item for script " + ItemID + ", part" + Part.Name + "@" + Part.AbsolutePosition); return(false); } //Try to see if this was rezzed from someone's inventory UserInventoryItemID = Part.FromUserInventoryItemID; //Try to find the avatar who started this. IScenePresence presence = World.GetScenePresence(Part.OwnerID); if (startInfo.ClearStateSaves) { m_ScriptEngine.StateSave.DeleteFrom(this); } //Now that the initial loading is complete, // we need to find the state save and start loading the info from it StateSave LastStateSave = m_ScriptEngine.StateSave.FindScriptStateSave(this); if (!reupload && Loading && LastStateSave != null) { //Deserialize the most important pieces first Source = LastStateSave.Source; } if (string.IsNullOrEmpty(Source)) { byte[] asset = Part.ParentEntity.Scene.AssetService.GetData(InventoryItem.AssetID.ToString()); if (null == asset) { MainConsole.Instance.ErrorFormat( "[ScriptData]: " + "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", InventoryItem.Name, InventoryItem.ItemID, Part.AbsolutePosition, Part.ParentEntity.Scene.RegionInfo.RegionName, InventoryItem.AssetID); ScriptEngine.ScriptProtection.RemoveScript(this); return(false); } Source = Utils.BytesToString(asset); } if (string.IsNullOrEmpty(Source)) { MainConsole.Instance.ErrorFormat( "[ScriptData]: " + "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", InventoryItem.Name, InventoryItem.ItemID, Part.AbsolutePosition, Part.ParentEntity.Scene.RegionInfo.RegionName, InventoryItem.AssetID); ScriptEngine.ScriptProtection.RemoveScript(this); return(false); } #region HTML Reader if (ScriptEngine.ScriptProtection.AllowHTMLLinking) { //Read the URL and load it. if (Source.Contains("#IncludeHTML ")) { string URL = ""; int line = Source.IndexOf("#IncludeHTML ", StringComparison.Ordinal); URL = Source.Remove(0, line); URL = URL.Replace("#IncludeHTML ", ""); URL = URL.Split('\n')[0]; string webSite = Utilities.ReadExternalWebsite(URL); Source = Source.Replace("#IncludeHTML " + URL, webSite); } } else { //Remove the line then if (Source.Contains("#IncludeHTML ")) { string URL = ""; int line = Source.IndexOf("#IncludeHTML ", StringComparison.Ordinal); URL = Source.Remove(0, line); URL = URL.Replace("#IncludeHTML ", ""); URL = URL.Split('\n')[0]; Source = Source.Replace("#IncludeHTML " + URL, ""); } } #endregion //Find the default state save DefaultState = m_ScriptEngine.Compiler.FindDefaultStateForScript(Source); State = DefaultState; //If the saved state exists, if it isn't a reupload (something changed), and if the assembly exists, load the state save if (!reupload && Loading && LastStateSave != null && File.Exists(LastStateSave.AssemblyName)) { //Retrive the previous assembly AssemblyName = LastStateSave.AssemblyName; } else { Compiled = false; //if (!reupload && Loading && LastStateSave != null && !LastStateSave.Compiled) // return false;//If we're trying to start up and we failed before, just give up if (reupload) { LastStateSave = null; //Close the previous script CloseAndDispose(false); //We don't want to back it up Interlocked.Increment(ref VersionID); m_ScriptEngine.MaintenanceThread.SetEventSchSetIgnoreNew(this, false); // accept new events } //Try to find a previously compiled script in this instance string PreviouslyCompiledAssemblyName = ScriptEngine.ScriptProtection.TryGetPreviouslyCompiledScript(Source); if (PreviouslyCompiledAssemblyName != null) { //Already exists in this instance, so we do not need to check whether it exists AssemblyName = PreviouslyCompiledAssemblyName; } else { try { m_ScriptEngine.Compiler.PerformScriptCompile(Source, Part.OwnerID, out AssemblyName); #region Errors and Warnings #region Errors string[] compileerrors = m_ScriptEngine.Compiler.GetErrors(); if (compileerrors.Length != 0) { string error = string.Empty; foreach (string compileerror in compileerrors) { error += compileerror; } DisplayUserNotification(error, "compiling", reupload, true); //It might have failed, but we still need to add it so that we can reuse this script data class later ScriptEngine.ScriptProtection.AddNewScript(this); m_ScriptEngine.StateSave.SaveStateTo(this, true); return(false); } #endregion #region Warnings if (m_ScriptEngine.ShowWarnings) { string[] compilewarnings = m_ScriptEngine.Compiler.GetWarnings(); if (compilewarnings != null && compilewarnings.Length != 0) { string error = string.Empty; foreach (string compileerror in compilewarnings) { error += compileerror; } DisplayUserNotification(error, "compiling", reupload, false); //It might have failed, but we still need to add it so that we can reuse this script data class later ScriptEngine.ScriptProtection.AddNewScript(this); return(false); } } #endregion #endregion } catch (Exception ex) { //LEAVE IT AS ToString() SO THAT WE GET THE STACK TRACE TOO DisplayUserNotification(ex.ToString(), "(exception) compiling", reupload, true); //It might have failed, but we still need to add it so that we can reuse this script data class later ScriptEngine.ScriptProtection.AddNewScript(this); return(false); } } } #if SHOWDEBUG MainConsole.Instance.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Stage 1 compile: " + (DateTime.Now.ToUniversalTime() - StartTime).TotalSeconds); #endif //Create the app domain if needed. try { Script = m_ScriptEngine.AppDomainManager.LoadScript(AssemblyName, "Script.ScriptClass", out AppDomain); if (Script == null) { return(false); } m_ScriptEngine.Compiler.FinishCompile(this, Script); //Add now so that we don't add it too early and give it the possibility to fail ScriptEngine.ScriptProtection.AddPreviouslyCompiled(Source, this); } catch (FileNotFoundException) // Not valid!!! { MainConsole.Instance.Error("[" + m_ScriptEngine.ScriptEngineName + "]: File not found in app domain creation. Corrupt state save! " + AssemblyName); ScriptEngine.ScriptProtection.RemovePreviouslyCompiled(Source); return(Start(startInfo)); // Lets restart the script if this happens } catch (Exception ex) { DisplayUserNotification(ex.ToString(), "app domain creation", reupload, true); //It might have failed, but we still need to add it so that we can reuse this script data class later ScriptEngine.ScriptProtection.AddNewScript(this); return(false); } Compiled = true; //We compiled successfully //ILease lease = (ILease)RemotingServices.GetLifetimeService(Script as MarshalByRefObject); //if (lease != null) //Its null if it is all running in the same app domain // lease.Register(Script.Sponsor); //If its a reupload, an avatar is waiting for the script errors if (reupload) { m_ScriptEngine.ScriptErrorReporter.AddError(ItemID, new ArrayList(new[] { "SUCCESSFULL" })); } #if SHOWDEBUG MainConsole.Instance.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Stage 2 compile: " + (DateTime.Now.ToUniversalTime() - StartTime).TotalSeconds); #endif SetApis(); //Now do the full state save finding now that we have an app domain. if (LastStateSave != null) { string assy = AssemblyName; // don't restore the assembly name, the one we have is right (if re-compiled or not) m_ScriptEngine.StateSave.Deserialize(this, LastStateSave); AssemblyName = assy; if (string.IsNullOrEmpty(State) && DefaultState != State) //Sometimes, "" is a valid state for other script languages { MainConsole.Instance.Warn("Resetting broken script save state\n" + " : " + InventoryItem.Name + ":" + Part.Name + " @ " + Part.AbsolutePosition + "\n in region " + Part.ParentEntity.Scene.RegionInfo.RegionName); State = DefaultState; m_ScriptEngine.StateSave.DeleteFrom(Part, LastStateSave.ItemID); m_ScriptEngine.StateSave.SaveStateTo(this, true); } else { // we get new rez events on sim restart, too // but if there is state, then we fire the change // event StartedFromSavedState = true; } // ItemID changes sometimes (not sure why, but observed it) // If so we want to clear out the old save state, // which would otherwise have hung around in the object forever if (LastStateSave.ItemID != ItemID) { m_ScriptEngine.StateSave.DeleteFrom(Part, LastStateSave.ItemID); m_ScriptEngine.StateSave.SaveStateTo(this, true); } } else { //Make a new state save now m_ScriptEngine.StateSave.SaveStateTo(this, true); } //Set the event flags Part.SetScriptEvents(ItemID, Script.GetStateEventFlags(State)); // Add it to our script memstruct so it can be found by other scripts ScriptEngine.ScriptProtection.AddNewScript(this); //All done, compiled successfully Loading = false; if (MainConsole.Instance.IsDebugEnabled) { TimeSpan time = (DateTime.Now.ToUniversalTime() - StartTime); MainConsole.Instance.Debug("[" + m_ScriptEngine.ScriptEngineName + "]: Started Script " + InventoryItem.Name + " in object " + Part.Name + "@" + Part.ParentEntity.RootChild.AbsolutePosition + (presence != null ? " by " + presence.Name : "") + " in region " + Part.ParentEntity.Scene.RegionInfo.RegionName + " in " + time.TotalSeconds + " seconds."); } return(true); }