Set eol
parent
33d82aa532
commit
0081c060d0
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,239 +1,239 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using OpenSim.Region.ScriptEngine.Common;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
public class AppDomainManager
|
||||
{
|
||||
|
||||
//
|
||||
// This class does AppDomain handling and loading/unloading of scripts in it.
|
||||
// It is instanced in "ScriptEngine" and controlled from "ScriptManager"
|
||||
//
|
||||
// 1. Create a new AppDomain if old one is full (or doesn't exist)
|
||||
// 2. Load scripts into AppDomain
|
||||
// 3. Unload scripts from AppDomain (stopping them and marking them as inactive)
|
||||
// 4. Unload AppDomain completely when all scripts in it has stopped
|
||||
//
|
||||
|
||||
|
||||
private int maxScriptsPerAppDomain = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Internal list of all AppDomains
|
||||
/// </summary>
|
||||
private List<AppDomainStructure> appDomains = new List<AppDomainStructure>();
|
||||
|
||||
/// <summary>
|
||||
/// Structure to keep track of data around AppDomain
|
||||
/// </summary>
|
||||
private class AppDomainStructure
|
||||
{
|
||||
/// <summary>
|
||||
/// The AppDomain itself
|
||||
/// </summary>
|
||||
public AppDomain CurrentAppDomain;
|
||||
|
||||
/// <summary>
|
||||
/// Number of scripts loaded into AppDomain
|
||||
/// </summary>
|
||||
public int ScriptsLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// Number of dead scripts
|
||||
/// </summary>
|
||||
public int ScriptsWaitingUnload;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current AppDomain
|
||||
/// </summary>
|
||||
private AppDomainStructure currentAD;
|
||||
|
||||
private object getLock = new object(); // Mutex
|
||||
private object freeLock = new object(); // Mutex
|
||||
|
||||
//private ScriptEngine m_scriptEngine;
|
||||
//public AppDomainManager(ScriptEngine scriptEngine)
|
||||
public AppDomainManager()
|
||||
{
|
||||
//m_scriptEngine = scriptEngine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a free AppDomain, creating one if necessary
|
||||
/// </summary>
|
||||
/// <returns>Free AppDomain</returns>
|
||||
private AppDomainStructure GetFreeAppDomain()
|
||||
{
|
||||
Console.WriteLine("Finding free AppDomain");
|
||||
lock (getLock)
|
||||
{
|
||||
// Current full?
|
||||
if (currentAD != null && currentAD.ScriptsLoaded >= maxScriptsPerAppDomain)
|
||||
{
|
||||
// Add it to AppDomains list and empty current
|
||||
appDomains.Add(currentAD);
|
||||
currentAD = null;
|
||||
}
|
||||
// No current
|
||||
if (currentAD == null)
|
||||
{
|
||||
// Create a new current AppDomain
|
||||
currentAD = new AppDomainStructure();
|
||||
currentAD.CurrentAppDomain = PrepareNewAppDomain();
|
||||
}
|
||||
|
||||
Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded);
|
||||
return currentAD;
|
||||
} // lock
|
||||
}
|
||||
|
||||
private int AppDomainNameCount;
|
||||
|
||||
/// <summary>
|
||||
/// Create and prepare a new AppDomain for scripts
|
||||
/// </summary>
|
||||
/// <returns>The new AppDomain</returns>
|
||||
private AppDomain PrepareNewAppDomain()
|
||||
{
|
||||
// Create and prepare a new AppDomain
|
||||
AppDomainNameCount++;
|
||||
// TODO: Currently security match current appdomain
|
||||
|
||||
// Construct and initialize settings for a second AppDomain.
|
||||
AppDomainSetup ads = new AppDomainSetup();
|
||||
ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
|
||||
ads.DisallowBindingRedirects = false;
|
||||
ads.DisallowCodeDownload = true;
|
||||
ads.LoaderOptimization = LoaderOptimization.MultiDomain; // Sounds good ;)
|
||||
ads.ShadowCopyFiles = "true"; // Enabled shadowing
|
||||
ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
|
||||
|
||||
AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads);
|
||||
Console.WriteLine("Loading: " +
|
||||
AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString());
|
||||
AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll"));
|
||||
|
||||
// Return the new AppDomain
|
||||
return AD;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unload appdomains that are full and have only dead scripts
|
||||
/// </summary>
|
||||
private void UnloadAppDomains()
|
||||
{
|
||||
lock (freeLock)
|
||||
{
|
||||
// Go through all
|
||||
foreach (AppDomainStructure ads in new ArrayList(appDomains))
|
||||
{
|
||||
// Don't process current AppDomain
|
||||
if (ads.CurrentAppDomain != currentAD.CurrentAppDomain)
|
||||
{
|
||||
// Not current AppDomain
|
||||
// Is number of unloaded bigger or equal to number of loaded?
|
||||
if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload)
|
||||
{
|
||||
Console.WriteLine("Found empty AppDomain, unloading");
|
||||
// Remove from internal list
|
||||
appDomains.Remove(ads);
|
||||
#if DEBUG
|
||||
long m = GC.GetTotalMemory(true);
|
||||
#endif
|
||||
// Unload
|
||||
AppDomain.Unload(ads.CurrentAppDomain);
|
||||
#if DEBUG
|
||||
Console.WriteLine("AppDomain unload freed " + (m - GC.GetTotalMemory(true)) +
|
||||
" bytes of memory");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} // foreach
|
||||
} // lock
|
||||
}
|
||||
|
||||
|
||||
public IScript LoadScript(string FileName)
|
||||
{
|
||||
// Find next available AppDomain to put it in
|
||||
AppDomainStructure FreeAppDomain = GetFreeAppDomain();
|
||||
|
||||
Console.WriteLine("Loading into AppDomain: " + FileName);
|
||||
IScript mbrt =
|
||||
(IScript)
|
||||
FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
|
||||
//Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
|
||||
FreeAppDomain.ScriptsLoaded++;
|
||||
|
||||
return mbrt;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Increase "dead script" counter for an AppDomain
|
||||
/// </summary>
|
||||
/// <param name="ad"></param>
|
||||
//[Obsolete("Needs fixing, needs a real purpose in life!!!")]
|
||||
public void StopScript(AppDomain ad)
|
||||
{
|
||||
lock (freeLock)
|
||||
{
|
||||
Console.WriteLine("Stopping script in AppDomain");
|
||||
// Check if it is current AppDomain
|
||||
if (currentAD.CurrentAppDomain == ad)
|
||||
{
|
||||
// Yes - increase
|
||||
currentAD.ScriptsWaitingUnload++;
|
||||
return;
|
||||
}
|
||||
|
||||
// Lopp through all AppDomains
|
||||
foreach (AppDomainStructure ads in new ArrayList(appDomains))
|
||||
{
|
||||
if (ads.CurrentAppDomain == ad)
|
||||
{
|
||||
// Found it
|
||||
ads.ScriptsWaitingUnload++;
|
||||
break;
|
||||
}
|
||||
} // foreach
|
||||
} // lock
|
||||
|
||||
UnloadAppDomains(); // Outsite lock, has its own GetLock
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using OpenSim.Region.ScriptEngine.Common;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
public class AppDomainManager
|
||||
{
|
||||
|
||||
//
|
||||
// This class does AppDomain handling and loading/unloading of scripts in it.
|
||||
// It is instanced in "ScriptEngine" and controlled from "ScriptManager"
|
||||
//
|
||||
// 1. Create a new AppDomain if old one is full (or doesn't exist)
|
||||
// 2. Load scripts into AppDomain
|
||||
// 3. Unload scripts from AppDomain (stopping them and marking them as inactive)
|
||||
// 4. Unload AppDomain completely when all scripts in it has stopped
|
||||
//
|
||||
|
||||
|
||||
private int maxScriptsPerAppDomain = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Internal list of all AppDomains
|
||||
/// </summary>
|
||||
private List<AppDomainStructure> appDomains = new List<AppDomainStructure>();
|
||||
|
||||
/// <summary>
|
||||
/// Structure to keep track of data around AppDomain
|
||||
/// </summary>
|
||||
private class AppDomainStructure
|
||||
{
|
||||
/// <summary>
|
||||
/// The AppDomain itself
|
||||
/// </summary>
|
||||
public AppDomain CurrentAppDomain;
|
||||
|
||||
/// <summary>
|
||||
/// Number of scripts loaded into AppDomain
|
||||
/// </summary>
|
||||
public int ScriptsLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// Number of dead scripts
|
||||
/// </summary>
|
||||
public int ScriptsWaitingUnload;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current AppDomain
|
||||
/// </summary>
|
||||
private AppDomainStructure currentAD;
|
||||
|
||||
private object getLock = new object(); // Mutex
|
||||
private object freeLock = new object(); // Mutex
|
||||
|
||||
//private ScriptEngine m_scriptEngine;
|
||||
//public AppDomainManager(ScriptEngine scriptEngine)
|
||||
public AppDomainManager()
|
||||
{
|
||||
//m_scriptEngine = scriptEngine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a free AppDomain, creating one if necessary
|
||||
/// </summary>
|
||||
/// <returns>Free AppDomain</returns>
|
||||
private AppDomainStructure GetFreeAppDomain()
|
||||
{
|
||||
Console.WriteLine("Finding free AppDomain");
|
||||
lock (getLock)
|
||||
{
|
||||
// Current full?
|
||||
if (currentAD != null && currentAD.ScriptsLoaded >= maxScriptsPerAppDomain)
|
||||
{
|
||||
// Add it to AppDomains list and empty current
|
||||
appDomains.Add(currentAD);
|
||||
currentAD = null;
|
||||
}
|
||||
// No current
|
||||
if (currentAD == null)
|
||||
{
|
||||
// Create a new current AppDomain
|
||||
currentAD = new AppDomainStructure();
|
||||
currentAD.CurrentAppDomain = PrepareNewAppDomain();
|
||||
}
|
||||
|
||||
Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded);
|
||||
return currentAD;
|
||||
} // lock
|
||||
}
|
||||
|
||||
private int AppDomainNameCount;
|
||||
|
||||
/// <summary>
|
||||
/// Create and prepare a new AppDomain for scripts
|
||||
/// </summary>
|
||||
/// <returns>The new AppDomain</returns>
|
||||
private AppDomain PrepareNewAppDomain()
|
||||
{
|
||||
// Create and prepare a new AppDomain
|
||||
AppDomainNameCount++;
|
||||
// TODO: Currently security match current appdomain
|
||||
|
||||
// Construct and initialize settings for a second AppDomain.
|
||||
AppDomainSetup ads = new AppDomainSetup();
|
||||
ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
|
||||
ads.DisallowBindingRedirects = false;
|
||||
ads.DisallowCodeDownload = true;
|
||||
ads.LoaderOptimization = LoaderOptimization.MultiDomain; // Sounds good ;)
|
||||
ads.ShadowCopyFiles = "true"; // Enabled shadowing
|
||||
ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
|
||||
|
||||
AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads);
|
||||
Console.WriteLine("Loading: " +
|
||||
AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString());
|
||||
AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll"));
|
||||
|
||||
// Return the new AppDomain
|
||||
return AD;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unload appdomains that are full and have only dead scripts
|
||||
/// </summary>
|
||||
private void UnloadAppDomains()
|
||||
{
|
||||
lock (freeLock)
|
||||
{
|
||||
// Go through all
|
||||
foreach (AppDomainStructure ads in new ArrayList(appDomains))
|
||||
{
|
||||
// Don't process current AppDomain
|
||||
if (ads.CurrentAppDomain != currentAD.CurrentAppDomain)
|
||||
{
|
||||
// Not current AppDomain
|
||||
// Is number of unloaded bigger or equal to number of loaded?
|
||||
if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload)
|
||||
{
|
||||
Console.WriteLine("Found empty AppDomain, unloading");
|
||||
// Remove from internal list
|
||||
appDomains.Remove(ads);
|
||||
#if DEBUG
|
||||
long m = GC.GetTotalMemory(true);
|
||||
#endif
|
||||
// Unload
|
||||
AppDomain.Unload(ads.CurrentAppDomain);
|
||||
#if DEBUG
|
||||
Console.WriteLine("AppDomain unload freed " + (m - GC.GetTotalMemory(true)) +
|
||||
" bytes of memory");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} // foreach
|
||||
} // lock
|
||||
}
|
||||
|
||||
|
||||
public IScript LoadScript(string FileName)
|
||||
{
|
||||
// Find next available AppDomain to put it in
|
||||
AppDomainStructure FreeAppDomain = GetFreeAppDomain();
|
||||
|
||||
Console.WriteLine("Loading into AppDomain: " + FileName);
|
||||
IScript mbrt =
|
||||
(IScript)
|
||||
FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
|
||||
//Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
|
||||
FreeAppDomain.ScriptsLoaded++;
|
||||
|
||||
return mbrt;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Increase "dead script" counter for an AppDomain
|
||||
/// </summary>
|
||||
/// <param name="ad"></param>
|
||||
//[Obsolete("Needs fixing, needs a real purpose in life!!!")]
|
||||
public void StopScript(AppDomain ad)
|
||||
{
|
||||
lock (freeLock)
|
||||
{
|
||||
Console.WriteLine("Stopping script in AppDomain");
|
||||
// Check if it is current AppDomain
|
||||
if (currentAD.CurrentAppDomain == ad)
|
||||
{
|
||||
// Yes - increase
|
||||
currentAD.ScriptsWaitingUnload++;
|
||||
return;
|
||||
}
|
||||
|
||||
// Lopp through all AppDomains
|
||||
foreach (AppDomainStructure ads in new ArrayList(appDomains))
|
||||
{
|
||||
if (ads.CurrentAppDomain == ad)
|
||||
{
|
||||
// Found it
|
||||
ads.ScriptsWaitingUnload++;
|
||||
break;
|
||||
}
|
||||
} // foreach
|
||||
} // lock
|
||||
|
||||
UnloadAppDomains(); // Outsite lock, has its own GetLock
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,58 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
public static class Common
|
||||
{
|
||||
public static bool debug = true;
|
||||
public static ScriptEngine mySE;
|
||||
|
||||
// This class just contains some static log stuff used for debugging.
|
||||
|
||||
//public delegate void SendToDebugEventDelegate(string Message);
|
||||
//public delegate void SendToLogEventDelegate(string Message);
|
||||
//static public event SendToDebugEventDelegate SendToDebugEvent;
|
||||
//static public event SendToLogEventDelegate SendToLogEvent;
|
||||
|
||||
public static void SendToDebug(string Message)
|
||||
{
|
||||
//if (Debug == true)
|
||||
mySE.Log.Verbose("ScriptEngine", "Debug: " + Message);
|
||||
//SendToDebugEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
|
||||
}
|
||||
|
||||
public static void SendToLog(string Message)
|
||||
{
|
||||
//if (Debug == true)
|
||||
mySE.Log.Verbose("ScriptEngine", "LOG: " + Message);
|
||||
//SendToLogEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
public static class Common
|
||||
{
|
||||
public static bool debug = true;
|
||||
public static ScriptEngine mySE;
|
||||
|
||||
// This class just contains some static log stuff used for debugging.
|
||||
|
||||
//public delegate void SendToDebugEventDelegate(string Message);
|
||||
//public delegate void SendToLogEventDelegate(string Message);
|
||||
//static public event SendToDebugEventDelegate SendToDebugEvent;
|
||||
//static public event SendToLogEventDelegate SendToLogEvent;
|
||||
|
||||
public static void SendToDebug(string Message)
|
||||
{
|
||||
//if (Debug == true)
|
||||
mySE.Log.Verbose("ScriptEngine", "Debug: " + Message);
|
||||
//SendToDebugEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
|
||||
}
|
||||
|
||||
public static void SendToLog(string Message)
|
||||
{
|
||||
//if (Debug == true)
|
||||
mySE.Log.Verbose("ScriptEngine", "LOG: " + Message);
|
||||
//SendToLogEvent("\r\n" + DateTime.Now.ToString("[HH:mm:ss] ") + Message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,260 +1,260 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using libsecondlife;
|
||||
using OpenSim.Framework;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class EventManager : OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents
|
||||
{
|
||||
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
|
||||
private ScriptEngine myScriptEngine;
|
||||
//public IScriptHost TEMP_OBJECT_ID;
|
||||
public EventManager(ScriptEngine _ScriptEngine, bool performHookUp)
|
||||
{
|
||||
myScriptEngine = _ScriptEngine;
|
||||
|
||||
// Hook up to events from OpenSim
|
||||
// We may not want to do it because someone is controlling us and will deliver events to us
|
||||
if (performHookUp)
|
||||
{
|
||||
myScriptEngine.Log.Verbose("ScriptEngine", "Hooking up to server events");
|
||||
myScriptEngine.World.EventManager.OnObjectGrab += touch_start;
|
||||
myScriptEngine.World.EventManager.OnRezScript += OnRezScript;
|
||||
myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript;
|
||||
// TODO: HOOK ALL EVENTS UP TO SERVER!
|
||||
}
|
||||
}
|
||||
|
||||
public void touch_start(uint localID, LLVector3 offsetPos, IClientAPI remoteClient)
|
||||
{
|
||||
// Add to queue for all scripts in ObjectID object
|
||||
myScriptEngine.m_EventQueueManager.AddToObjectQueue(localID, "touch_start", new object[] {(int) 1});
|
||||
}
|
||||
|
||||
public void OnRezScript(uint localID, LLUUID itemID, string script)
|
||||
{
|
||||
Console.WriteLine("OnRezScript localID: " + localID + " LLUID: " + itemID.ToString() + " Size: " +
|
||||
script.Length);
|
||||
myScriptEngine.m_ScriptManager.StartScript(localID, itemID, script);
|
||||
}
|
||||
|
||||
public void OnRemoveScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
Console.WriteLine("OnRemoveScript localID: " + localID + " LLUID: " + itemID.ToString());
|
||||
myScriptEngine.m_ScriptManager.StopScript(
|
||||
localID,
|
||||
itemID
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Replace placeholders below
|
||||
// NOTE! THE PARAMETERS FOR THESE FUNCTIONS ARE NOT CORRECT!
|
||||
// These needs to be hooked up to OpenSim during init of this class
|
||||
// then queued in EventQueueManager.
|
||||
// When queued in EventQueueManager they need to be LSL compatible (name and params)
|
||||
|
||||
public void state_exit(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "state_exit");
|
||||
}
|
||||
|
||||
public void touch(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "touch");
|
||||
}
|
||||
|
||||
public void touch_end(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "touch_end");
|
||||
}
|
||||
|
||||
public void collision_start(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision_start");
|
||||
}
|
||||
|
||||
public void collision(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision");
|
||||
}
|
||||
|
||||
public void collision_end(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision_end");
|
||||
}
|
||||
|
||||
public void land_collision_start(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision_start");
|
||||
}
|
||||
|
||||
public void land_collision(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision");
|
||||
}
|
||||
|
||||
public void land_collision_end(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision_end");
|
||||
}
|
||||
|
||||
// Handled by long commands
|
||||
public void timer(uint localID, LLUUID itemID)
|
||||
{
|
||||
//myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "");
|
||||
}
|
||||
|
||||
public void listen(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "listen");
|
||||
}
|
||||
|
||||
public void on_rez(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "on_rez");
|
||||
}
|
||||
|
||||
public void sensor(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "sensor");
|
||||
}
|
||||
|
||||
public void no_sensor(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "no_sensor");
|
||||
}
|
||||
|
||||
public void control(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "control");
|
||||
}
|
||||
|
||||
public void money(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "money");
|
||||
}
|
||||
|
||||
public void email(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "email");
|
||||
}
|
||||
|
||||
public void at_target(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "at_target");
|
||||
}
|
||||
|
||||
public void not_at_target(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "not_at_target");
|
||||
}
|
||||
|
||||
public void at_rot_target(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "at_rot_target");
|
||||
}
|
||||
|
||||
public void not_at_rot_target(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "not_at_rot_target");
|
||||
}
|
||||
|
||||
public void run_time_permissions(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "run_time_permissions");
|
||||
}
|
||||
|
||||
public void changed(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "changed");
|
||||
}
|
||||
|
||||
public void attach(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "attach");
|
||||
}
|
||||
|
||||
public void dataserver(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "dataserver");
|
||||
}
|
||||
|
||||
public void link_message(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "link_message");
|
||||
}
|
||||
|
||||
public void moving_start(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "moving_start");
|
||||
}
|
||||
|
||||
public void moving_end(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "moving_end");
|
||||
}
|
||||
|
||||
public void object_rez(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "object_rez");
|
||||
}
|
||||
|
||||
public void remote_data(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "remote_data");
|
||||
}
|
||||
|
||||
// Handled by long commands
|
||||
public void http_response(uint localID, LLUUID itemID)
|
||||
{
|
||||
// myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "http_response");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using libsecondlife;
|
||||
using OpenSim.Framework;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class EventManager : OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.RemoteEvents
|
||||
{
|
||||
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
|
||||
private ScriptEngine myScriptEngine;
|
||||
//public IScriptHost TEMP_OBJECT_ID;
|
||||
public EventManager(ScriptEngine _ScriptEngine, bool performHookUp)
|
||||
{
|
||||
myScriptEngine = _ScriptEngine;
|
||||
|
||||
// Hook up to events from OpenSim
|
||||
// We may not want to do it because someone is controlling us and will deliver events to us
|
||||
if (performHookUp)
|
||||
{
|
||||
myScriptEngine.Log.Verbose("ScriptEngine", "Hooking up to server events");
|
||||
myScriptEngine.World.EventManager.OnObjectGrab += touch_start;
|
||||
myScriptEngine.World.EventManager.OnRezScript += OnRezScript;
|
||||
myScriptEngine.World.EventManager.OnRemoveScript += OnRemoveScript;
|
||||
// TODO: HOOK ALL EVENTS UP TO SERVER!
|
||||
}
|
||||
}
|
||||
|
||||
public void touch_start(uint localID, LLVector3 offsetPos, IClientAPI remoteClient)
|
||||
{
|
||||
// Add to queue for all scripts in ObjectID object
|
||||
myScriptEngine.m_EventQueueManager.AddToObjectQueue(localID, "touch_start", new object[] {(int) 1});
|
||||
}
|
||||
|
||||
public void OnRezScript(uint localID, LLUUID itemID, string script)
|
||||
{
|
||||
Console.WriteLine("OnRezScript localID: " + localID + " LLUID: " + itemID.ToString() + " Size: " +
|
||||
script.Length);
|
||||
myScriptEngine.m_ScriptManager.StartScript(localID, itemID, script);
|
||||
}
|
||||
|
||||
public void OnRemoveScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
Console.WriteLine("OnRemoveScript localID: " + localID + " LLUID: " + itemID.ToString());
|
||||
myScriptEngine.m_ScriptManager.StopScript(
|
||||
localID,
|
||||
itemID
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Replace placeholders below
|
||||
// NOTE! THE PARAMETERS FOR THESE FUNCTIONS ARE NOT CORRECT!
|
||||
// These needs to be hooked up to OpenSim during init of this class
|
||||
// then queued in EventQueueManager.
|
||||
// When queued in EventQueueManager they need to be LSL compatible (name and params)
|
||||
|
||||
public void state_exit(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "state_exit");
|
||||
}
|
||||
|
||||
public void touch(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "touch");
|
||||
}
|
||||
|
||||
public void touch_end(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "touch_end");
|
||||
}
|
||||
|
||||
public void collision_start(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision_start");
|
||||
}
|
||||
|
||||
public void collision(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision");
|
||||
}
|
||||
|
||||
public void collision_end(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "collision_end");
|
||||
}
|
||||
|
||||
public void land_collision_start(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision_start");
|
||||
}
|
||||
|
||||
public void land_collision(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision");
|
||||
}
|
||||
|
||||
public void land_collision_end(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "land_collision_end");
|
||||
}
|
||||
|
||||
// Handled by long commands
|
||||
public void timer(uint localID, LLUUID itemID)
|
||||
{
|
||||
//myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "");
|
||||
}
|
||||
|
||||
public void listen(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "listen");
|
||||
}
|
||||
|
||||
public void on_rez(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "on_rez");
|
||||
}
|
||||
|
||||
public void sensor(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "sensor");
|
||||
}
|
||||
|
||||
public void no_sensor(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "no_sensor");
|
||||
}
|
||||
|
||||
public void control(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "control");
|
||||
}
|
||||
|
||||
public void money(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "money");
|
||||
}
|
||||
|
||||
public void email(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "email");
|
||||
}
|
||||
|
||||
public void at_target(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "at_target");
|
||||
}
|
||||
|
||||
public void not_at_target(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "not_at_target");
|
||||
}
|
||||
|
||||
public void at_rot_target(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "at_rot_target");
|
||||
}
|
||||
|
||||
public void not_at_rot_target(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "not_at_rot_target");
|
||||
}
|
||||
|
||||
public void run_time_permissions(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "run_time_permissions");
|
||||
}
|
||||
|
||||
public void changed(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "changed");
|
||||
}
|
||||
|
||||
public void attach(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "attach");
|
||||
}
|
||||
|
||||
public void dataserver(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "dataserver");
|
||||
}
|
||||
|
||||
public void link_message(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "link_message");
|
||||
}
|
||||
|
||||
public void moving_start(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "moving_start");
|
||||
}
|
||||
|
||||
public void moving_end(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "moving_end");
|
||||
}
|
||||
|
||||
public void object_rez(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "object_rez");
|
||||
}
|
||||
|
||||
public void remote_data(uint localID, LLUUID itemID)
|
||||
{
|
||||
myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "remote_data");
|
||||
}
|
||||
|
||||
// Handled by long commands
|
||||
public void http_response(uint localID, LLUUID itemID)
|
||||
{
|
||||
// myScriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "http_response");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,364 +1,364 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Environment.Scenes.Scripting;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
/// <summary>
|
||||
/// EventQueueManager handles event queues
|
||||
/// Events are queued and executed in separate thread
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class EventQueueManager
|
||||
{
|
||||
|
||||
//
|
||||
// Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine".
|
||||
//
|
||||
// Class purpose is to queue and execute functions that are received by "EventManager":
|
||||
// - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution.
|
||||
// - allowing us to prioritize and control execution of script functions.
|
||||
// Class can use multiple threads for simultaneous execution. Mutexes are used for thread safety.
|
||||
//
|
||||
// 1. Hold an execution queue for scripts
|
||||
// 2. Use threads to process queue, each thread executes one script function on each pass.
|
||||
// 3. Catch any script error and process it
|
||||
//
|
||||
//
|
||||
// Notes:
|
||||
// * Current execution load balancing is optimized for 1 thread, and can cause unfair execute balancing between scripts.
|
||||
// Not noticeable unless server is under high load.
|
||||
// * This class contains the number of threads used for script executions. Since we are not microthreading scripts yet,
|
||||
// increase number of threads to allow more concurrent script executions in OpenSim.
|
||||
//
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// List of threads processing event queue
|
||||
/// </summary>
|
||||
private List<Thread> eventQueueThreads = new List<Thread>();
|
||||
|
||||
private object queueLock = new object(); // Mutex lock object
|
||||
|
||||
/// <summary>
|
||||
/// How many ms to sleep if queue is empty
|
||||
/// </summary>
|
||||
private int nothingToDoSleepms = 50;
|
||||
|
||||
/// <summary>
|
||||
/// How many threads to process queue with
|
||||
/// </summary>
|
||||
private int numberOfThreads = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Queue containing events waiting to be executed
|
||||
/// </summary>
|
||||
private Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>();
|
||||
|
||||
/// <summary>
|
||||
/// Queue item structure
|
||||
/// </summary>
|
||||
private struct QueueItemStruct
|
||||
{
|
||||
public uint localID;
|
||||
public LLUUID itemID;
|
||||
public string functionName;
|
||||
public object[] param;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of localID locks for mutex processing of script events
|
||||
/// </summary>
|
||||
private List<uint> objectLocks = new List<uint>();
|
||||
|
||||
private object tryLockLock = new object(); // Mutex lock object
|
||||
|
||||
private ScriptEngine m_ScriptEngine;
|
||||
|
||||
public EventQueueManager(ScriptEngine _ScriptEngine)
|
||||
{
|
||||
m_ScriptEngine = _ScriptEngine;
|
||||
|
||||
//
|
||||
// Start event queue processing threads (worker threads)
|
||||
//
|
||||
for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++)
|
||||
{
|
||||
Thread EventQueueThread = new Thread(EventQueueThreadLoop);
|
||||
eventQueueThreads.Add(EventQueueThread);
|
||||
EventQueueThread.IsBackground = true;
|
||||
EventQueueThread.Priority = ThreadPriority.BelowNormal;
|
||||
EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount;
|
||||
EventQueueThread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
~EventQueueManager()
|
||||
{
|
||||
// Kill worker threads
|
||||
foreach (Thread EventQueueThread in new ArrayList(eventQueueThreads))
|
||||
{
|
||||
if (EventQueueThread != null && EventQueueThread.IsAlive == true)
|
||||
{
|
||||
try
|
||||
{
|
||||
EventQueueThread.Abort();
|
||||
EventQueueThread.Join();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
eventQueueThreads.Clear();
|
||||
// Todo: Clean up our queues
|
||||
eventQueue.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue processing thread loop
|
||||
/// </summary>
|
||||
private void EventQueueThreadLoop()
|
||||
{
|
||||
//myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned");
|
||||
try
|
||||
{
|
||||
QueueItemStruct BlankQIS = new QueueItemStruct();
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
QueueItemStruct QIS = BlankQIS;
|
||||
bool GotItem = false;
|
||||
|
||||
if (eventQueue.Count == 0)
|
||||
{
|
||||
// Nothing to do? Sleep a bit waiting for something to do
|
||||
Thread.Sleep(nothingToDoSleepms);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something in queue, process
|
||||
//myScriptEngine.m_logger.Verbose("ScriptEngine", "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 (queueLock)
|
||||
{
|
||||
GotItem = false;
|
||||
for (int qc = 0; qc < eventQueue.Count; qc++)
|
||||
{
|
||||
// Get queue item
|
||||
QIS = eventQueue.Dequeue();
|
||||
|
||||
// Check if object is being processed by someone else
|
||||
if (TryLock(QIS.localID) == false)
|
||||
{
|
||||
// Object is already being processed, requeue it
|
||||
eventQueue.Enqueue(QIS);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have lock on an object and can process it
|
||||
GotItem = true;
|
||||
break;
|
||||
}
|
||||
} // go through queue
|
||||
} // lock
|
||||
|
||||
if (GotItem == true)
|
||||
{
|
||||
// Execute function
|
||||
try
|
||||
{
|
||||
#if DEBUG
|
||||
m_ScriptEngine.Log.Debug("ScriptEngine", "Executing event:\r\n"
|
||||
+ "QIS.localID: " + QIS.localID
|
||||
+ ", QIS.itemID: " + QIS.itemID
|
||||
+ ", QIS.functionName: " + QIS.functionName);
|
||||
#endif
|
||||
m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID,
|
||||
QIS.functionName, QIS.param);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// DISPLAY ERROR INWORLD
|
||||
string text = "Error executing script function \"" + QIS.functionName + "\":\r\n";
|
||||
//if (e.InnerException != null)
|
||||
//{
|
||||
// Send inner exception
|
||||
text += e.InnerException.Message.ToString();
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
text += "\r\n";
|
||||
// Send normal
|
||||
text += e.Message.ToString();
|
||||
//}
|
||||
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(Helpers.StringToField(text), ChatTypeEnum.Say, 0,
|
||||
m_host.AbsolutePosition, m_host.Name, m_host.UUID);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// T oconsole
|
||||
m_ScriptEngine.Log.Error("ScriptEngine",
|
||||
"Unable to send text in-world:\r\n" + text);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ReleaseLock(QIS.localID);
|
||||
}
|
||||
}
|
||||
} // Something in queue
|
||||
}
|
||||
catch (ThreadAbortException tae)
|
||||
{
|
||||
throw tae;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_ScriptEngine.Log.Error("ScriptEngine", "Exception in EventQueueThreadLoop: " + e.ToString());
|
||||
}
|
||||
} // while
|
||||
} // try
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
//myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to get a mutex lock on localID
|
||||
/// </summary>
|
||||
/// <param name="localID"></param>
|
||||
/// <returns></returns>
|
||||
private bool TryLock(uint localID)
|
||||
{
|
||||
lock (tryLockLock)
|
||||
{
|
||||
if (objectLocks.Contains(localID) == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
objectLocks.Add(localID);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release mutex lock on localID
|
||||
/// </summary>
|
||||
/// <param name="localID"></param>
|
||||
private void ReleaseLock(uint localID)
|
||||
{
|
||||
lock (tryLockLock)
|
||||
{
|
||||
if (objectLocks.Contains(localID) == true)
|
||||
{
|
||||
objectLocks.Remove(localID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Add event to event execution queue
|
||||
/// </summary>
|
||||
/// <param name="localID"></param>
|
||||
/// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
|
||||
/// <param name="param">Array of parameters to match event mask</param>
|
||||
public void AddToObjectQueue(uint localID, string FunctionName, params object[] param)
|
||||
{
|
||||
// Determine all scripts in Object and add to their queue
|
||||
//myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName);
|
||||
|
||||
|
||||
// Do we have any scripts in this object at all? If not, return
|
||||
if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false)
|
||||
{
|
||||
//Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID.");
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<LLUUID, IScript>.KeyCollection scriptKeys =
|
||||
m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID);
|
||||
|
||||
foreach (LLUUID itemID in scriptKeys)
|
||||
{
|
||||
// Add to each script in that object
|
||||
// TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter?
|
||||
AddToScriptQueue(localID, itemID, FunctionName, param);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add event to event execution queue
|
||||
/// </summary>
|
||||
/// <param name="localID"></param>
|
||||
/// <param name="itemID"></param>
|
||||
/// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
|
||||
/// <param name="param">Array of parameters to match event mask</param>
|
||||
public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, params object[] param)
|
||||
{
|
||||
lock (queueLock)
|
||||
{
|
||||
// Create a structure and add data
|
||||
QueueItemStruct QIS = new QueueItemStruct();
|
||||
QIS.localID = localID;
|
||||
QIS.itemID = itemID;
|
||||
QIS.functionName = FunctionName;
|
||||
QIS.param = param;
|
||||
|
||||
// Add it to queue
|
||||
eventQueue.Enqueue(QIS);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Environment.Scenes.Scripting;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
/// <summary>
|
||||
/// EventQueueManager handles event queues
|
||||
/// Events are queued and executed in separate thread
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class EventQueueManager
|
||||
{
|
||||
|
||||
//
|
||||
// Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine".
|
||||
//
|
||||
// Class purpose is to queue and execute functions that are received by "EventManager":
|
||||
// - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution.
|
||||
// - allowing us to prioritize and control execution of script functions.
|
||||
// Class can use multiple threads for simultaneous execution. Mutexes are used for thread safety.
|
||||
//
|
||||
// 1. Hold an execution queue for scripts
|
||||
// 2. Use threads to process queue, each thread executes one script function on each pass.
|
||||
// 3. Catch any script error and process it
|
||||
//
|
||||
//
|
||||
// Notes:
|
||||
// * Current execution load balancing is optimized for 1 thread, and can cause unfair execute balancing between scripts.
|
||||
// Not noticeable unless server is under high load.
|
||||
// * This class contains the number of threads used for script executions. Since we are not microthreading scripts yet,
|
||||
// increase number of threads to allow more concurrent script executions in OpenSim.
|
||||
//
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// List of threads processing event queue
|
||||
/// </summary>
|
||||
private List<Thread> eventQueueThreads = new List<Thread>();
|
||||
|
||||
private object queueLock = new object(); // Mutex lock object
|
||||
|
||||
/// <summary>
|
||||
/// How many ms to sleep if queue is empty
|
||||
/// </summary>
|
||||
private int nothingToDoSleepms = 50;
|
||||
|
||||
/// <summary>
|
||||
/// How many threads to process queue with
|
||||
/// </summary>
|
||||
private int numberOfThreads = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Queue containing events waiting to be executed
|
||||
/// </summary>
|
||||
private Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>();
|
||||
|
||||
/// <summary>
|
||||
/// Queue item structure
|
||||
/// </summary>
|
||||
private struct QueueItemStruct
|
||||
{
|
||||
public uint localID;
|
||||
public LLUUID itemID;
|
||||
public string functionName;
|
||||
public object[] param;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of localID locks for mutex processing of script events
|
||||
/// </summary>
|
||||
private List<uint> objectLocks = new List<uint>();
|
||||
|
||||
private object tryLockLock = new object(); // Mutex lock object
|
||||
|
||||
private ScriptEngine m_ScriptEngine;
|
||||
|
||||
public EventQueueManager(ScriptEngine _ScriptEngine)
|
||||
{
|
||||
m_ScriptEngine = _ScriptEngine;
|
||||
|
||||
//
|
||||
// Start event queue processing threads (worker threads)
|
||||
//
|
||||
for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++)
|
||||
{
|
||||
Thread EventQueueThread = new Thread(EventQueueThreadLoop);
|
||||
eventQueueThreads.Add(EventQueueThread);
|
||||
EventQueueThread.IsBackground = true;
|
||||
EventQueueThread.Priority = ThreadPriority.BelowNormal;
|
||||
EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount;
|
||||
EventQueueThread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
~EventQueueManager()
|
||||
{
|
||||
// Kill worker threads
|
||||
foreach (Thread EventQueueThread in new ArrayList(eventQueueThreads))
|
||||
{
|
||||
if (EventQueueThread != null && EventQueueThread.IsAlive == true)
|
||||
{
|
||||
try
|
||||
{
|
||||
EventQueueThread.Abort();
|
||||
EventQueueThread.Join();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
eventQueueThreads.Clear();
|
||||
// Todo: Clean up our queues
|
||||
eventQueue.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue processing thread loop
|
||||
/// </summary>
|
||||
private void EventQueueThreadLoop()
|
||||
{
|
||||
//myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned");
|
||||
try
|
||||
{
|
||||
QueueItemStruct BlankQIS = new QueueItemStruct();
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
QueueItemStruct QIS = BlankQIS;
|
||||
bool GotItem = false;
|
||||
|
||||
if (eventQueue.Count == 0)
|
||||
{
|
||||
// Nothing to do? Sleep a bit waiting for something to do
|
||||
Thread.Sleep(nothingToDoSleepms);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something in queue, process
|
||||
//myScriptEngine.m_logger.Verbose("ScriptEngine", "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 (queueLock)
|
||||
{
|
||||
GotItem = false;
|
||||
for (int qc = 0; qc < eventQueue.Count; qc++)
|
||||
{
|
||||
// Get queue item
|
||||
QIS = eventQueue.Dequeue();
|
||||
|
||||
// Check if object is being processed by someone else
|
||||
if (TryLock(QIS.localID) == false)
|
||||
{
|
||||
// Object is already being processed, requeue it
|
||||
eventQueue.Enqueue(QIS);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have lock on an object and can process it
|
||||
GotItem = true;
|
||||
break;
|
||||
}
|
||||
} // go through queue
|
||||
} // lock
|
||||
|
||||
if (GotItem == true)
|
||||
{
|
||||
// Execute function
|
||||
try
|
||||
{
|
||||
#if DEBUG
|
||||
m_ScriptEngine.Log.Debug("ScriptEngine", "Executing event:\r\n"
|
||||
+ "QIS.localID: " + QIS.localID
|
||||
+ ", QIS.itemID: " + QIS.itemID
|
||||
+ ", QIS.functionName: " + QIS.functionName);
|
||||
#endif
|
||||
m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID,
|
||||
QIS.functionName, QIS.param);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// DISPLAY ERROR INWORLD
|
||||
string text = "Error executing script function \"" + QIS.functionName + "\":\r\n";
|
||||
//if (e.InnerException != null)
|
||||
//{
|
||||
// Send inner exception
|
||||
text += e.InnerException.Message.ToString();
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
text += "\r\n";
|
||||
// Send normal
|
||||
text += e.Message.ToString();
|
||||
//}
|
||||
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(Helpers.StringToField(text), ChatTypeEnum.Say, 0,
|
||||
m_host.AbsolutePosition, m_host.Name, m_host.UUID);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// T oconsole
|
||||
m_ScriptEngine.Log.Error("ScriptEngine",
|
||||
"Unable to send text in-world:\r\n" + text);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ReleaseLock(QIS.localID);
|
||||
}
|
||||
}
|
||||
} // Something in queue
|
||||
}
|
||||
catch (ThreadAbortException tae)
|
||||
{
|
||||
throw tae;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_ScriptEngine.Log.Error("ScriptEngine", "Exception in EventQueueThreadLoop: " + e.ToString());
|
||||
}
|
||||
} // while
|
||||
} // try
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
//myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to get a mutex lock on localID
|
||||
/// </summary>
|
||||
/// <param name="localID"></param>
|
||||
/// <returns></returns>
|
||||
private bool TryLock(uint localID)
|
||||
{
|
||||
lock (tryLockLock)
|
||||
{
|
||||
if (objectLocks.Contains(localID) == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
objectLocks.Add(localID);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release mutex lock on localID
|
||||
/// </summary>
|
||||
/// <param name="localID"></param>
|
||||
private void ReleaseLock(uint localID)
|
||||
{
|
||||
lock (tryLockLock)
|
||||
{
|
||||
if (objectLocks.Contains(localID) == true)
|
||||
{
|
||||
objectLocks.Remove(localID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Add event to event execution queue
|
||||
/// </summary>
|
||||
/// <param name="localID"></param>
|
||||
/// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
|
||||
/// <param name="param">Array of parameters to match event mask</param>
|
||||
public void AddToObjectQueue(uint localID, string FunctionName, params object[] param)
|
||||
{
|
||||
// Determine all scripts in Object and add to their queue
|
||||
//myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName);
|
||||
|
||||
|
||||
// Do we have any scripts in this object at all? If not, return
|
||||
if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false)
|
||||
{
|
||||
//Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID.");
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<LLUUID, IScript>.KeyCollection scriptKeys =
|
||||
m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID);
|
||||
|
||||
foreach (LLUUID itemID in scriptKeys)
|
||||
{
|
||||
// Add to each script in that object
|
||||
// TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter?
|
||||
AddToScriptQueue(localID, itemID, FunctionName, param);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add event to event execution queue
|
||||
/// </summary>
|
||||
/// <param name="localID"></param>
|
||||
/// <param name="itemID"></param>
|
||||
/// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
|
||||
/// <param name="param">Array of parameters to match event mask</param>
|
||||
public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, params object[] param)
|
||||
{
|
||||
lock (queueLock)
|
||||
{
|
||||
// Create a structure and add data
|
||||
QueueItemStruct QIS = new QueueItemStruct();
|
||||
QIS.localID = localID;
|
||||
QIS.itemID = itemID;
|
||||
QIS.functionName = FunctionName;
|
||||
QIS.param = param;
|
||||
|
||||
// Add it to queue
|
||||
eventQueue.Enqueue(QIS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,295 +1,295 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using OpenSim.Region.Environment.Interfaces;
|
||||
using OpenSim.Region.Environment.Modules;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
|
||||
/// </summary>
|
||||
public class LSLLongCmdHandler
|
||||
{
|
||||
private Thread cmdHandlerThread;
|
||||
private int cmdHandlerThreadCycleSleepms = 100;
|
||||
|
||||
private ScriptEngine m_ScriptEngine;
|
||||
|
||||
public LSLLongCmdHandler(ScriptEngine _ScriptEngine)
|
||||
{
|
||||
m_ScriptEngine = _ScriptEngine;
|
||||
|
||||
// Start the thread that will be doing the work
|
||||
cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
|
||||
cmdHandlerThread.Name = "CmdHandlerThread";
|
||||
cmdHandlerThread.Priority = ThreadPriority.BelowNormal;
|
||||
cmdHandlerThread.IsBackground = true;
|
||||
cmdHandlerThread.Start();
|
||||
}
|
||||
|
||||
~LSLLongCmdHandler()
|
||||
{
|
||||
// Shut down thread
|
||||
try
|
||||
{
|
||||
if (cmdHandlerThread != null)
|
||||
{
|
||||
if (cmdHandlerThread.IsAlive == true)
|
||||
{
|
||||
cmdHandlerThread.Abort();
|
||||
cmdHandlerThread.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void CmdHandlerThreadLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Check timers
|
||||
CheckTimerEvents();
|
||||
Thread.Sleep(25);
|
||||
// Check HttpRequests
|
||||
CheckHttpRequests();
|
||||
Thread.Sleep(25);
|
||||
// Check XMLRPCRequests
|
||||
CheckXMLRPCRequests();
|
||||
Thread.Sleep(25);
|
||||
// Check Listeners
|
||||
CheckListeners();
|
||||
Thread.Sleep(25);
|
||||
|
||||
// Sleep before next cycle
|
||||
//Thread.Sleep(cmdHandlerThreadCycleSleepms);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a specific script (and all its pending commands)
|
||||
/// </summary>
|
||||
/// <param name="m_localID"></param>
|
||||
/// <param name="m_itemID"></param>
|
||||
public void RemoveScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
// Remove a specific script
|
||||
|
||||
// Remove from: Timers
|
||||
UnSetTimerEvents(localID, itemID);
|
||||
// Remove from: HttpRequest
|
||||
IHttpRequests iHttpReq =
|
||||
m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
|
||||
iHttpReq.StopHttpRequest(localID, itemID);
|
||||
}
|
||||
|
||||
#region TIMER
|
||||
|
||||
//
|
||||
// TIMER
|
||||
//
|
||||
private class TimerClass
|
||||
{
|
||||
public uint localID;
|
||||
public LLUUID itemID;
|
||||
public double interval;
|
||||
public DateTime next;
|
||||
}
|
||||
|
||||
private List<TimerClass> Timers = new List<TimerClass>();
|
||||
private object TimerListLock = new object();
|
||||
|
||||
public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec)
|
||||
{
|
||||
Console.WriteLine("SetTimerEvent");
|
||||
|
||||
// Always remove first, in case this is a re-set
|
||||
UnSetTimerEvents(m_localID, m_itemID);
|
||||
if (sec == 0) // Disabling timer
|
||||
return;
|
||||
|
||||
// Add to timer
|
||||
TimerClass ts = new TimerClass();
|
||||
ts.localID = m_localID;
|
||||
ts.itemID = m_itemID;
|
||||
ts.interval = sec;
|
||||
ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
|
||||
lock (TimerListLock)
|
||||
{
|
||||
Timers.Add(ts);
|
||||
}
|
||||
}
|
||||
|
||||
public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID)
|
||||
{
|
||||
// Remove from timer
|
||||
lock (TimerListLock)
|
||||
{
|
||||
List<TimerClass> NewTimers = new List<TimerClass>();
|
||||
foreach (TimerClass ts in Timers)
|
||||
{
|
||||
if (ts.localID != m_localID && ts.itemID != m_itemID)
|
||||
{
|
||||
NewTimers.Add(ts);
|
||||
}
|
||||
}
|
||||
Timers.Clear();
|
||||
Timers = NewTimers;
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckTimerEvents()
|
||||
{
|
||||
// Nothing to do here?
|
||||
if (Timers.Count == 0)
|
||||
return;
|
||||
|
||||
lock (TimerListLock)
|
||||
{
|
||||
// Go through all timers
|
||||
foreach (TimerClass ts in Timers)
|
||||
{
|
||||
// Time has passed?
|
||||
if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
|
||||
{
|
||||
// Add it to queue
|
||||
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer",
|
||||
new object[] {});
|
||||
// set next interval
|
||||
|
||||
|
||||
ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
|
||||
}
|
||||
}
|
||||
} // lock
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HTTP REQUEST
|
||||
|
||||
public void CheckHttpRequests()
|
||||
{
|
||||
if (m_ScriptEngine.World == null)
|
||||
return;
|
||||
|
||||
IHttpRequests iHttpReq =
|
||||
m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
|
||||
|
||||
HttpRequestClass httpInfo = null;
|
||||
|
||||
if (iHttpReq != null)
|
||||
httpInfo = iHttpReq.GetNextCompletedRequest();
|
||||
|
||||
while (httpInfo != null)
|
||||
{
|
||||
//Console.WriteLine("PICKED HTTP REQ:" + httpInfo.response_body + httpInfo.status);
|
||||
|
||||
// Deliver data to prim's remote_data handler
|
||||
//
|
||||
// TODO: Returning null for metadata, since the lsl function
|
||||
// only returns the byte for HTTP_BODY_TRUNCATED, which is not
|
||||
// implemented here yet anyway. Should be fixed if/when maxsize
|
||||
// is supported
|
||||
|
||||
object[] resobj = new object[]
|
||||
{
|
||||
httpInfo.reqID.ToString(), httpInfo.status, null, httpInfo.response_body
|
||||
};
|
||||
|
||||
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
|
||||
httpInfo.localID, httpInfo.itemID, "http_response", resobj
|
||||
);
|
||||
|
||||
httpInfo.Stop();
|
||||
httpInfo = null;
|
||||
|
||||
httpInfo = iHttpReq.GetNextCompletedRequest();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void CheckXMLRPCRequests()
|
||||
{
|
||||
if (m_ScriptEngine.World == null)
|
||||
return;
|
||||
|
||||
IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
|
||||
|
||||
if (xmlrpc != null)
|
||||
{
|
||||
while (xmlrpc.hasRequests())
|
||||
{
|
||||
RPCRequestInfo rInfo = xmlrpc.GetNextRequest();
|
||||
//Console.WriteLine("PICKED REQUEST");
|
||||
|
||||
//Deliver data to prim's remote_data handler
|
||||
object[] resobj = new object[]
|
||||
{
|
||||
2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), "",
|
||||
rInfo.GetIntValue(),
|
||||
rInfo.GetStrVal()
|
||||
};
|
||||
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
|
||||
rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", resobj
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckListeners()
|
||||
{
|
||||
if (m_ScriptEngine.World == null)
|
||||
return;
|
||||
IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
|
||||
|
||||
while (comms.HasMessages())
|
||||
{
|
||||
ListenerInfo lInfo = comms.GetNextMessage();
|
||||
|
||||
//Deliver data to prim's listen handler
|
||||
object[] resobj = new object[]
|
||||
{
|
||||
lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage()
|
||||
};
|
||||
|
||||
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
|
||||
lInfo.GetLocalID(), lInfo.GetItemID(), "listen", resobj
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using OpenSim.Region.Environment.Interfaces;
|
||||
using OpenSim.Region.Environment.Modules;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
|
||||
/// </summary>
|
||||
public class LSLLongCmdHandler
|
||||
{
|
||||
private Thread cmdHandlerThread;
|
||||
private int cmdHandlerThreadCycleSleepms = 100;
|
||||
|
||||
private ScriptEngine m_ScriptEngine;
|
||||
|
||||
public LSLLongCmdHandler(ScriptEngine _ScriptEngine)
|
||||
{
|
||||
m_ScriptEngine = _ScriptEngine;
|
||||
|
||||
// Start the thread that will be doing the work
|
||||
cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
|
||||
cmdHandlerThread.Name = "CmdHandlerThread";
|
||||
cmdHandlerThread.Priority = ThreadPriority.BelowNormal;
|
||||
cmdHandlerThread.IsBackground = true;
|
||||
cmdHandlerThread.Start();
|
||||
}
|
||||
|
||||
~LSLLongCmdHandler()
|
||||
{
|
||||
// Shut down thread
|
||||
try
|
||||
{
|
||||
if (cmdHandlerThread != null)
|
||||
{
|
||||
if (cmdHandlerThread.IsAlive == true)
|
||||
{
|
||||
cmdHandlerThread.Abort();
|
||||
cmdHandlerThread.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void CmdHandlerThreadLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Check timers
|
||||
CheckTimerEvents();
|
||||
Thread.Sleep(25);
|
||||
// Check HttpRequests
|
||||
CheckHttpRequests();
|
||||
Thread.Sleep(25);
|
||||
// Check XMLRPCRequests
|
||||
CheckXMLRPCRequests();
|
||||
Thread.Sleep(25);
|
||||
// Check Listeners
|
||||
CheckListeners();
|
||||
Thread.Sleep(25);
|
||||
|
||||
// Sleep before next cycle
|
||||
//Thread.Sleep(cmdHandlerThreadCycleSleepms);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a specific script (and all its pending commands)
|
||||
/// </summary>
|
||||
/// <param name="m_localID"></param>
|
||||
/// <param name="m_itemID"></param>
|
||||
public void RemoveScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
// Remove a specific script
|
||||
|
||||
// Remove from: Timers
|
||||
UnSetTimerEvents(localID, itemID);
|
||||
// Remove from: HttpRequest
|
||||
IHttpRequests iHttpReq =
|
||||
m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
|
||||
iHttpReq.StopHttpRequest(localID, itemID);
|
||||
}
|
||||
|
||||
#region TIMER
|
||||
|
||||
//
|
||||
// TIMER
|
||||
//
|
||||
private class TimerClass
|
||||
{
|
||||
public uint localID;
|
||||
public LLUUID itemID;
|
||||
public double interval;
|
||||
public DateTime next;
|
||||
}
|
||||
|
||||
private List<TimerClass> Timers = new List<TimerClass>();
|
||||
private object TimerListLock = new object();
|
||||
|
||||
public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec)
|
||||
{
|
||||
Console.WriteLine("SetTimerEvent");
|
||||
|
||||
// Always remove first, in case this is a re-set
|
||||
UnSetTimerEvents(m_localID, m_itemID);
|
||||
if (sec == 0) // Disabling timer
|
||||
return;
|
||||
|
||||
// Add to timer
|
||||
TimerClass ts = new TimerClass();
|
||||
ts.localID = m_localID;
|
||||
ts.itemID = m_itemID;
|
||||
ts.interval = sec;
|
||||
ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
|
||||
lock (TimerListLock)
|
||||
{
|
||||
Timers.Add(ts);
|
||||
}
|
||||
}
|
||||
|
||||
public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID)
|
||||
{
|
||||
// Remove from timer
|
||||
lock (TimerListLock)
|
||||
{
|
||||
List<TimerClass> NewTimers = new List<TimerClass>();
|
||||
foreach (TimerClass ts in Timers)
|
||||
{
|
||||
if (ts.localID != m_localID && ts.itemID != m_itemID)
|
||||
{
|
||||
NewTimers.Add(ts);
|
||||
}
|
||||
}
|
||||
Timers.Clear();
|
||||
Timers = NewTimers;
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckTimerEvents()
|
||||
{
|
||||
// Nothing to do here?
|
||||
if (Timers.Count == 0)
|
||||
return;
|
||||
|
||||
lock (TimerListLock)
|
||||
{
|
||||
// Go through all timers
|
||||
foreach (TimerClass ts in Timers)
|
||||
{
|
||||
// Time has passed?
|
||||
if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
|
||||
{
|
||||
// Add it to queue
|
||||
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer",
|
||||
new object[] {});
|
||||
// set next interval
|
||||
|
||||
|
||||
ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
|
||||
}
|
||||
}
|
||||
} // lock
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HTTP REQUEST
|
||||
|
||||
public void CheckHttpRequests()
|
||||
{
|
||||
if (m_ScriptEngine.World == null)
|
||||
return;
|
||||
|
||||
IHttpRequests iHttpReq =
|
||||
m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
|
||||
|
||||
HttpRequestClass httpInfo = null;
|
||||
|
||||
if (iHttpReq != null)
|
||||
httpInfo = iHttpReq.GetNextCompletedRequest();
|
||||
|
||||
while (httpInfo != null)
|
||||
{
|
||||
//Console.WriteLine("PICKED HTTP REQ:" + httpInfo.response_body + httpInfo.status);
|
||||
|
||||
// Deliver data to prim's remote_data handler
|
||||
//
|
||||
// TODO: Returning null for metadata, since the lsl function
|
||||
// only returns the byte for HTTP_BODY_TRUNCATED, which is not
|
||||
// implemented here yet anyway. Should be fixed if/when maxsize
|
||||
// is supported
|
||||
|
||||
object[] resobj = new object[]
|
||||
{
|
||||
httpInfo.reqID.ToString(), httpInfo.status, null, httpInfo.response_body
|
||||
};
|
||||
|
||||
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
|
||||
httpInfo.localID, httpInfo.itemID, "http_response", resobj
|
||||
);
|
||||
|
||||
httpInfo.Stop();
|
||||
httpInfo = null;
|
||||
|
||||
httpInfo = iHttpReq.GetNextCompletedRequest();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void CheckXMLRPCRequests()
|
||||
{
|
||||
if (m_ScriptEngine.World == null)
|
||||
return;
|
||||
|
||||
IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
|
||||
|
||||
if (xmlrpc != null)
|
||||
{
|
||||
while (xmlrpc.hasRequests())
|
||||
{
|
||||
RPCRequestInfo rInfo = xmlrpc.GetNextRequest();
|
||||
//Console.WriteLine("PICKED REQUEST");
|
||||
|
||||
//Deliver data to prim's remote_data handler
|
||||
object[] resobj = new object[]
|
||||
{
|
||||
2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), "",
|
||||
rInfo.GetIntValue(),
|
||||
rInfo.GetStrVal()
|
||||
};
|
||||
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
|
||||
rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", resobj
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckListeners()
|
||||
{
|
||||
if (m_ScriptEngine.World == null)
|
||||
return;
|
||||
IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
|
||||
|
||||
while (comms.HasMessages())
|
||||
{
|
||||
ListenerInfo lInfo = comms.GetNextMessage();
|
||||
|
||||
//Deliver data to prim's listen handler
|
||||
object[] resobj = new object[]
|
||||
{
|
||||
lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage()
|
||||
};
|
||||
|
||||
m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
|
||||
lInfo.GetLocalID(), lInfo.GetItemID(), "listen", resobj
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,132 +1,132 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using Nini.Config;
|
||||
using OpenSim.Framework.Console;
|
||||
using OpenSim.Region.Environment.Interfaces;
|
||||
using OpenSim.Region.Environment.Scenes;
|
||||
using OpenSim.Region.ScriptEngine.Common;
|
||||
using OpenSim.Region.ScriptEngine.Common.ScriptEngineBase;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the root object for ScriptEngine. Objects access each other trough this class.
|
||||
/// </summary>
|
||||
///
|
||||
[Serializable]
|
||||
public abstract class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine
|
||||
{
|
||||
public Scene World;
|
||||
public EventManager m_EventManager; // Handles and queues incoming events from OpenSim
|
||||
public EventQueueManager m_EventQueueManager; // Executes events
|
||||
public ScriptManager m_ScriptManager; // Load, unload and execute scripts
|
||||
public AppDomainManager m_AppDomainManager;
|
||||
public LSLLongCmdHandler m_LSLLongCmdHandler;
|
||||
|
||||
public ScriptManager GetScriptManager()
|
||||
{
|
||||
return _GetScriptManager();
|
||||
}
|
||||
public abstract ScriptManager _GetScriptManager();
|
||||
|
||||
private LogBase m_log;
|
||||
|
||||
public ScriptEngine()
|
||||
{
|
||||
//Common.SendToDebug("ScriptEngine Object Initialized");
|
||||
Common.mySE = this;
|
||||
}
|
||||
|
||||
public LogBase Log
|
||||
{
|
||||
get { return m_log; }
|
||||
}
|
||||
|
||||
public void InitializeEngine(Scene Sceneworld, LogBase logger, bool HookUpToServer, ScriptManager newScriptManager)
|
||||
{
|
||||
World = Sceneworld;
|
||||
m_log = logger;
|
||||
|
||||
Log.Verbose("ScriptEngine", "DotNet & LSL ScriptEngine initializing");
|
||||
|
||||
//m_logger.Status("ScriptEngine", "InitializeEngine");
|
||||
|
||||
// Create all objects we'll be using
|
||||
m_EventQueueManager = new EventQueueManager(this);
|
||||
m_EventManager = new EventManager(this, HookUpToServer);
|
||||
m_ScriptManager = newScriptManager;
|
||||
//m_ScriptManager = new ScriptManager(this);
|
||||
m_AppDomainManager = new AppDomainManager();
|
||||
m_LSLLongCmdHandler = new LSLLongCmdHandler(this);
|
||||
|
||||
// Should we iterate the region for scripts that needs starting?
|
||||
// Or can we assume we are loaded before anything else so we can use proper events?
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
// We are shutting down
|
||||
}
|
||||
|
||||
ScriptServerInterfaces.RemoteEvents ScriptServerInterfaces.ScriptEngine.EventManager()
|
||||
{
|
||||
return this.m_EventManager;
|
||||
}
|
||||
|
||||
|
||||
#region IRegionModule
|
||||
|
||||
public abstract void Initialise(Scene scene, IConfigSource config);
|
||||
|
||||
public void PostInitialise()
|
||||
{
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "DotNetEngine"; }
|
||||
}
|
||||
|
||||
public bool IsSharedModule
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using Nini.Config;
|
||||
using OpenSim.Framework.Console;
|
||||
using OpenSim.Region.Environment.Interfaces;
|
||||
using OpenSim.Region.Environment.Scenes;
|
||||
using OpenSim.Region.ScriptEngine.Common;
|
||||
using OpenSim.Region.ScriptEngine.Common.ScriptEngineBase;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the root object for ScriptEngine. Objects access each other trough this class.
|
||||
/// </summary>
|
||||
///
|
||||
[Serializable]
|
||||
public abstract class ScriptEngine : IRegionModule, OpenSim.Region.ScriptEngine.Common.ScriptServerInterfaces.ScriptEngine
|
||||
{
|
||||
public Scene World;
|
||||
public EventManager m_EventManager; // Handles and queues incoming events from OpenSim
|
||||
public EventQueueManager m_EventQueueManager; // Executes events
|
||||
public ScriptManager m_ScriptManager; // Load, unload and execute scripts
|
||||
public AppDomainManager m_AppDomainManager;
|
||||
public LSLLongCmdHandler m_LSLLongCmdHandler;
|
||||
|
||||
public ScriptManager GetScriptManager()
|
||||
{
|
||||
return _GetScriptManager();
|
||||
}
|
||||
public abstract ScriptManager _GetScriptManager();
|
||||
|
||||
private LogBase m_log;
|
||||
|
||||
public ScriptEngine()
|
||||
{
|
||||
//Common.SendToDebug("ScriptEngine Object Initialized");
|
||||
Common.mySE = this;
|
||||
}
|
||||
|
||||
public LogBase Log
|
||||
{
|
||||
get { return m_log; }
|
||||
}
|
||||
|
||||
public void InitializeEngine(Scene Sceneworld, LogBase logger, bool HookUpToServer, ScriptManager newScriptManager)
|
||||
{
|
||||
World = Sceneworld;
|
||||
m_log = logger;
|
||||
|
||||
Log.Verbose("ScriptEngine", "DotNet & LSL ScriptEngine initializing");
|
||||
|
||||
//m_logger.Status("ScriptEngine", "InitializeEngine");
|
||||
|
||||
// Create all objects we'll be using
|
||||
m_EventQueueManager = new EventQueueManager(this);
|
||||
m_EventManager = new EventManager(this, HookUpToServer);
|
||||
m_ScriptManager = newScriptManager;
|
||||
//m_ScriptManager = new ScriptManager(this);
|
||||
m_AppDomainManager = new AppDomainManager();
|
||||
m_LSLLongCmdHandler = new LSLLongCmdHandler(this);
|
||||
|
||||
// Should we iterate the region for scripts that needs starting?
|
||||
// Or can we assume we are loaded before anything else so we can use proper events?
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
// We are shutting down
|
||||
}
|
||||
|
||||
ScriptServerInterfaces.RemoteEvents ScriptServerInterfaces.ScriptEngine.EventManager()
|
||||
{
|
||||
return this.m_EventManager;
|
||||
}
|
||||
|
||||
|
||||
#region IRegionModule
|
||||
|
||||
public abstract void Initialise(Scene scene, IConfigSource config);
|
||||
|
||||
public void PostInitialise()
|
||||
{
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "DotNetEngine"; }
|
||||
}
|
||||
|
||||
public bool IsSharedModule
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -1,348 +1,348 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Environment.Scenes;
|
||||
using OpenSim.Region.ScriptEngine.Common;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads scripts
|
||||
/// Compiles them if necessary
|
||||
/// Execute functions for EventQueueManager (Sends them to script on other AppDomain for execution)
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
// This class is as close as you get to the script without being inside script class. It handles all the dirty work for other classes.
|
||||
// * Keeps track of running scripts
|
||||
// * Compiles script if necessary (through "Compiler")
|
||||
// * Loads script (through "AppDomainManager" called from for example "EventQueueManager")
|
||||
// * Executes functions inside script (called from for example "EventQueueManager" class)
|
||||
// * Unloads script (through "AppDomainManager" called from for example "EventQueueManager")
|
||||
// * Dedicated load/unload thread, and queues loading/unloading.
|
||||
// This so that scripts starting or stopping will not slow down other theads or whole system.
|
||||
//
|
||||
[Serializable]
|
||||
public abstract class ScriptManager
|
||||
{
|
||||
#region Declares
|
||||
|
||||
private Thread scriptLoadUnloadThread;
|
||||
private int scriptLoadUnloadThread_IdleSleepms = 100;
|
||||
private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
|
||||
|
||||
|
||||
// Load/Unload structure
|
||||
private struct LUStruct
|
||||
{
|
||||
public uint localID;
|
||||
public LLUUID itemID;
|
||||
public string script;
|
||||
public LUType Action;
|
||||
}
|
||||
|
||||
private enum LUType
|
||||
{
|
||||
Unknown = 0,
|
||||
Load = 1,
|
||||
Unload = 2
|
||||
}
|
||||
|
||||
// Object<string, Script<string, script>>
|
||||
// IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
|
||||
// Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
|
||||
public Dictionary<uint, Dictionary<LLUUID, IScript>> Scripts =
|
||||
new Dictionary<uint, Dictionary<LLUUID, IScript>>();
|
||||
|
||||
public Scene World
|
||||
{
|
||||
get { return m_scriptEngine.World; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Object init/shutdown
|
||||
|
||||
public ScriptEngineBase.ScriptEngine m_scriptEngine;
|
||||
|
||||
public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine)
|
||||
{
|
||||
m_scriptEngine = scriptEngine;
|
||||
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
|
||||
scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop);
|
||||
scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread";
|
||||
scriptLoadUnloadThread.IsBackground = true;
|
||||
scriptLoadUnloadThread.Priority = ThreadPriority.BelowNormal;
|
||||
scriptLoadUnloadThread.Start();
|
||||
}
|
||||
|
||||
~ScriptManager()
|
||||
{
|
||||
// Abort load/unload thread
|
||||
try
|
||||
{
|
||||
if (scriptLoadUnloadThread != null)
|
||||
{
|
||||
if (scriptLoadUnloadThread.IsAlive == true)
|
||||
{
|
||||
scriptLoadUnloadThread.Abort();
|
||||
scriptLoadUnloadThread.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Load / Unload scripts (Thread loop)
|
||||
|
||||
private void ScriptLoadUnloadThreadLoop()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (LUQueue.Count == 0)
|
||||
Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
|
||||
if (LUQueue.Count > 0)
|
||||
{
|
||||
LUStruct item = LUQueue.Dequeue();
|
||||
lock (startStopLock) // Lock so we have only 1 thread working on loading/unloading of scripts
|
||||
{
|
||||
if (item.Action == LUType.Unload)
|
||||
{
|
||||
_StopScript(item.localID, item.itemID);
|
||||
}
|
||||
if (item.Action == LUType.Load)
|
||||
{
|
||||
_StartScript(item.localID, item.itemID, item.script);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ThreadAbortException tae)
|
||||
{
|
||||
string a = tae.ToString();
|
||||
a = "";
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper functions
|
||||
|
||||
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
//Console.WriteLine("ScriptManager.CurrentDomain_AssemblyResolve: " + args.Name);
|
||||
return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Start/Stop/Reset script
|
||||
|
||||
private readonly Object startStopLock = new Object();
|
||||
|
||||
/// <summary>
|
||||
/// Fetches, loads and hooks up a script to an objects events
|
||||
/// </summary>
|
||||
/// <param name="itemID"></param>
|
||||
/// <param name="localID"></param>
|
||||
public void StartScript(uint localID, LLUUID itemID, string Script)
|
||||
{
|
||||
LUStruct ls = new LUStruct();
|
||||
ls.localID = localID;
|
||||
ls.itemID = itemID;
|
||||
ls.script = Script;
|
||||
ls.Action = LUType.Load;
|
||||
LUQueue.Enqueue(ls);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables and unloads a script
|
||||
/// </summary>
|
||||
/// <param name="localID"></param>
|
||||
/// <param name="itemID"></param>
|
||||
public void StopScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
LUStruct ls = new LUStruct();
|
||||
ls.localID = localID;
|
||||
ls.itemID = itemID;
|
||||
ls.Action = LUType.Unload;
|
||||
LUQueue.Enqueue(ls);
|
||||
}
|
||||
|
||||
// Create a new instance of the compiler (reuse)
|
||||
//private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler();
|
||||
|
||||
public abstract void _StartScript(uint localID, LLUUID itemID, string Script);
|
||||
|
||||
public abstract void _StopScript(uint localID, LLUUID itemID);
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Perform event execution in script
|
||||
|
||||
/// <summary>
|
||||
/// Execute a LL-event-function in Script
|
||||
/// </summary>
|
||||
/// <param name="localID">Object the script is located in</param>
|
||||
/// <param name="itemID">Script ID</param>
|
||||
/// <param name="FunctionName">Name of function</param>
|
||||
/// <param name="args">Arguments to pass to function</param>
|
||||
internal void ExecuteEvent(uint localID, LLUUID itemID, string FunctionName, object[] args)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
|
||||
#endif
|
||||
// Execute a function in the script
|
||||
//m_scriptEngine.Log.Verbose("ScriptEngine", "Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
|
||||
//ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
|
||||
IScript Script = GetScript(localID, itemID);
|
||||
if (Script == null)
|
||||
return;
|
||||
#if DEBUG
|
||||
Console.WriteLine("ScriptEngine: Executing event: " + FunctionName);
|
||||
#endif
|
||||
// Must be done in correct AppDomain, so leaving it up to the script itself
|
||||
Script.Exec.ExecuteEvent(FunctionName, args);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal functions to keep track of script
|
||||
|
||||
public Dictionary<LLUUID, IScript>.KeyCollection GetScriptKeys(uint localID)
|
||||
{
|
||||
if (Scripts.ContainsKey(localID) == false)
|
||||
return null;
|
||||
|
||||
Dictionary<LLUUID, IScript> Obj;
|
||||
Scripts.TryGetValue(localID, out Obj);
|
||||
|
||||
return Obj.Keys;
|
||||
}
|
||||
|
||||
public IScript GetScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
if (Scripts.ContainsKey(localID) == false)
|
||||
return null;
|
||||
|
||||
Dictionary<LLUUID, IScript> Obj;
|
||||
Scripts.TryGetValue(localID, out Obj);
|
||||
if (Obj.ContainsKey(itemID) == false)
|
||||
return null;
|
||||
|
||||
// Get script
|
||||
IScript Script;
|
||||
Obj.TryGetValue(itemID, out Script);
|
||||
|
||||
return Script;
|
||||
}
|
||||
|
||||
public void SetScript(uint localID, LLUUID itemID, IScript Script)
|
||||
{
|
||||
// Create object if it doesn't exist
|
||||
if (Scripts.ContainsKey(localID) == false)
|
||||
{
|
||||
Scripts.Add(localID, new Dictionary<LLUUID, IScript>());
|
||||
}
|
||||
|
||||
// Delete script if it exists
|
||||
Dictionary<LLUUID, IScript> Obj;
|
||||
Scripts.TryGetValue(localID, out Obj);
|
||||
if (Obj.ContainsKey(itemID) == true)
|
||||
Obj.Remove(itemID);
|
||||
|
||||
// Add to object
|
||||
Obj.Add(itemID, Script);
|
||||
}
|
||||
|
||||
public void RemoveScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
// Don't have that object?
|
||||
if (Scripts.ContainsKey(localID) == false)
|
||||
return;
|
||||
|
||||
// Delete script if it exists
|
||||
Dictionary<LLUUID, IScript> Obj;
|
||||
Scripts.TryGetValue(localID, out Obj);
|
||||
if (Obj.ContainsKey(itemID) == true)
|
||||
Obj.Remove(itemID);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public void ResetScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
string script = GetScript(localID, itemID).Source;
|
||||
StopScript(localID, itemID);
|
||||
StartScript(localID, itemID, script);
|
||||
}
|
||||
|
||||
|
||||
#region Script serialization/deserialization
|
||||
|
||||
public void GetSerializedScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
// Serialize the script and return it
|
||||
// Should not be a problem
|
||||
FileStream fs = File.Create("SERIALIZED_SCRIPT_" + itemID);
|
||||
BinaryFormatter b = new BinaryFormatter();
|
||||
b.Serialize(fs, GetScript(localID, itemID));
|
||||
fs.Close();
|
||||
}
|
||||
|
||||
public void PutSerializedScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
// Deserialize the script and inject it into an AppDomain
|
||||
|
||||
// How to inject into an AppDomain?
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Threading;
|
||||
using libsecondlife;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Environment.Scenes;
|
||||
using OpenSim.Region.ScriptEngine.Common;
|
||||
|
||||
namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads scripts
|
||||
/// Compiles them if necessary
|
||||
/// Execute functions for EventQueueManager (Sends them to script on other AppDomain for execution)
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
// This class is as close as you get to the script without being inside script class. It handles all the dirty work for other classes.
|
||||
// * Keeps track of running scripts
|
||||
// * Compiles script if necessary (through "Compiler")
|
||||
// * Loads script (through "AppDomainManager" called from for example "EventQueueManager")
|
||||
// * Executes functions inside script (called from for example "EventQueueManager" class)
|
||||
// * Unloads script (through "AppDomainManager" called from for example "EventQueueManager")
|
||||
// * Dedicated load/unload thread, and queues loading/unloading.
|
||||
// This so that scripts starting or stopping will not slow down other theads or whole system.
|
||||
//
|
||||
[Serializable]
|
||||
public abstract class ScriptManager
|
||||
{
|
||||
#region Declares
|
||||
|
||||
private Thread scriptLoadUnloadThread;
|
||||
private int scriptLoadUnloadThread_IdleSleepms = 100;
|
||||
private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
|
||||
|
||||
|
||||
// Load/Unload structure
|
||||
private struct LUStruct
|
||||
{
|
||||
public uint localID;
|
||||
public LLUUID itemID;
|
||||
public string script;
|
||||
public LUType Action;
|
||||
}
|
||||
|
||||
private enum LUType
|
||||
{
|
||||
Unknown = 0,
|
||||
Load = 1,
|
||||
Unload = 2
|
||||
}
|
||||
|
||||
// Object<string, Script<string, script>>
|
||||
// IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
|
||||
// Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
|
||||
public Dictionary<uint, Dictionary<LLUUID, IScript>> Scripts =
|
||||
new Dictionary<uint, Dictionary<LLUUID, IScript>>();
|
||||
|
||||
public Scene World
|
||||
{
|
||||
get { return m_scriptEngine.World; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Object init/shutdown
|
||||
|
||||
public ScriptEngineBase.ScriptEngine m_scriptEngine;
|
||||
|
||||
public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine)
|
||||
{
|
||||
m_scriptEngine = scriptEngine;
|
||||
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
|
||||
scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop);
|
||||
scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread";
|
||||
scriptLoadUnloadThread.IsBackground = true;
|
||||
scriptLoadUnloadThread.Priority = ThreadPriority.BelowNormal;
|
||||
scriptLoadUnloadThread.Start();
|
||||
}
|
||||
|
||||
~ScriptManager()
|
||||
{
|
||||
// Abort load/unload thread
|
||||
try
|
||||
{
|
||||
if (scriptLoadUnloadThread != null)
|
||||
{
|
||||
if (scriptLoadUnloadThread.IsAlive == true)
|
||||
{
|
||||
scriptLoadUnloadThread.Abort();
|
||||
scriptLoadUnloadThread.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Load / Unload scripts (Thread loop)
|
||||
|
||||
private void ScriptLoadUnloadThreadLoop()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (LUQueue.Count == 0)
|
||||
Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
|
||||
if (LUQueue.Count > 0)
|
||||
{
|
||||
LUStruct item = LUQueue.Dequeue();
|
||||
lock (startStopLock) // Lock so we have only 1 thread working on loading/unloading of scripts
|
||||
{
|
||||
if (item.Action == LUType.Unload)
|
||||
{
|
||||
_StopScript(item.localID, item.itemID);
|
||||
}
|
||||
if (item.Action == LUType.Load)
|
||||
{
|
||||
_StartScript(item.localID, item.itemID, item.script);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ThreadAbortException tae)
|
||||
{
|
||||
string a = tae.ToString();
|
||||
a = "";
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper functions
|
||||
|
||||
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
//Console.WriteLine("ScriptManager.CurrentDomain_AssemblyResolve: " + args.Name);
|
||||
return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Start/Stop/Reset script
|
||||
|
||||
private readonly Object startStopLock = new Object();
|
||||
|
||||
/// <summary>
|
||||
/// Fetches, loads and hooks up a script to an objects events
|
||||
/// </summary>
|
||||
/// <param name="itemID"></param>
|
||||
/// <param name="localID"></param>
|
||||
public void StartScript(uint localID, LLUUID itemID, string Script)
|
||||
{
|
||||
LUStruct ls = new LUStruct();
|
||||
ls.localID = localID;
|
||||
ls.itemID = itemID;
|
||||
ls.script = Script;
|
||||
ls.Action = LUType.Load;
|
||||
LUQueue.Enqueue(ls);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables and unloads a script
|
||||
/// </summary>
|
||||
/// <param name="localID"></param>
|
||||
/// <param name="itemID"></param>
|
||||
public void StopScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
LUStruct ls = new LUStruct();
|
||||
ls.localID = localID;
|
||||
ls.itemID = itemID;
|
||||
ls.Action = LUType.Unload;
|
||||
LUQueue.Enqueue(ls);
|
||||
}
|
||||
|
||||
// Create a new instance of the compiler (reuse)
|
||||
//private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler();
|
||||
|
||||
public abstract void _StartScript(uint localID, LLUUID itemID, string Script);
|
||||
|
||||
public abstract void _StopScript(uint localID, LLUUID itemID);
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Perform event execution in script
|
||||
|
||||
/// <summary>
|
||||
/// Execute a LL-event-function in Script
|
||||
/// </summary>
|
||||
/// <param name="localID">Object the script is located in</param>
|
||||
/// <param name="itemID">Script ID</param>
|
||||
/// <param name="FunctionName">Name of function</param>
|
||||
/// <param name="args">Arguments to pass to function</param>
|
||||
internal void ExecuteEvent(uint localID, LLUUID itemID, string FunctionName, object[] args)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
|
||||
#endif
|
||||
// Execute a function in the script
|
||||
//m_scriptEngine.Log.Verbose("ScriptEngine", "Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
|
||||
//ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
|
||||
IScript Script = GetScript(localID, itemID);
|
||||
if (Script == null)
|
||||
return;
|
||||
#if DEBUG
|
||||
Console.WriteLine("ScriptEngine: Executing event: " + FunctionName);
|
||||
#endif
|
||||
// Must be done in correct AppDomain, so leaving it up to the script itself
|
||||
Script.Exec.ExecuteEvent(FunctionName, args);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal functions to keep track of script
|
||||
|
||||
public Dictionary<LLUUID, IScript>.KeyCollection GetScriptKeys(uint localID)
|
||||
{
|
||||
if (Scripts.ContainsKey(localID) == false)
|
||||
return null;
|
||||
|
||||
Dictionary<LLUUID, IScript> Obj;
|
||||
Scripts.TryGetValue(localID, out Obj);
|
||||
|
||||
return Obj.Keys;
|
||||
}
|
||||
|
||||
public IScript GetScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
if (Scripts.ContainsKey(localID) == false)
|
||||
return null;
|
||||
|
||||
Dictionary<LLUUID, IScript> Obj;
|
||||
Scripts.TryGetValue(localID, out Obj);
|
||||
if (Obj.ContainsKey(itemID) == false)
|
||||
return null;
|
||||
|
||||
// Get script
|
||||
IScript Script;
|
||||
Obj.TryGetValue(itemID, out Script);
|
||||
|
||||
return Script;
|
||||
}
|
||||
|
||||
public void SetScript(uint localID, LLUUID itemID, IScript Script)
|
||||
{
|
||||
// Create object if it doesn't exist
|
||||
if (Scripts.ContainsKey(localID) == false)
|
||||
{
|
||||
Scripts.Add(localID, new Dictionary<LLUUID, IScript>());
|
||||
}
|
||||
|
||||
// Delete script if it exists
|
||||
Dictionary<LLUUID, IScript> Obj;
|
||||
Scripts.TryGetValue(localID, out Obj);
|
||||
if (Obj.ContainsKey(itemID) == true)
|
||||
Obj.Remove(itemID);
|
||||
|
||||
// Add to object
|
||||
Obj.Add(itemID, Script);
|
||||
}
|
||||
|
||||
public void RemoveScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
// Don't have that object?
|
||||
if (Scripts.ContainsKey(localID) == false)
|
||||
return;
|
||||
|
||||
// Delete script if it exists
|
||||
Dictionary<LLUUID, IScript> Obj;
|
||||
Scripts.TryGetValue(localID, out Obj);
|
||||
if (Obj.ContainsKey(itemID) == true)
|
||||
Obj.Remove(itemID);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public void ResetScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
string script = GetScript(localID, itemID).Source;
|
||||
StopScript(localID, itemID);
|
||||
StartScript(localID, itemID, script);
|
||||
}
|
||||
|
||||
|
||||
#region Script serialization/deserialization
|
||||
|
||||
public void GetSerializedScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
// Serialize the script and return it
|
||||
// Should not be a problem
|
||||
FileStream fs = File.Create("SERIALIZED_SCRIPT_" + itemID);
|
||||
BinaryFormatter b = new BinaryFormatter();
|
||||
b.Serialize(fs, GetScript(localID, itemID));
|
||||
fs.Close();
|
||||
}
|
||||
|
||||
public void PutSerializedScript(uint localID, LLUUID itemID)
|
||||
{
|
||||
// Deserialize the script and inject it into an AppDomain
|
||||
|
||||
// How to inject into an AppDomain?
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue