mirror of
https://github.com/opensim/opensim.git
synced 2026-08-04 08:06:27 +08:00
bad merge?
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics; //for [DebuggerNonUserCode]
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -161,6 +162,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
private Dictionary<UUID, IScriptInstance> m_Scripts =
|
||||
new Dictionary<UUID, IScriptInstance>();
|
||||
|
||||
private OpenMetaverse.ReaderWriterLockSlim m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
|
||||
|
||||
// Maps the asset ID to the assembly
|
||||
|
||||
private Dictionary<UUID, string> m_Assemblies =
|
||||
@@ -183,6 +186,71 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
IWorkItemResult m_CurrentCompile = null;
|
||||
private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>();
|
||||
|
||||
private void lockScriptsForRead(bool locked)
|
||||
{
|
||||
if (locked)
|
||||
{
|
||||
if (m_scriptsLock.RecursiveReadCount > 0)
|
||||
{
|
||||
m_log.Error("[XEngine.m_Scripts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
|
||||
m_scriptsLock.ExitReadLock();
|
||||
}
|
||||
if (m_scriptsLock.RecursiveWriteCount > 0)
|
||||
{
|
||||
m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
|
||||
m_scriptsLock.ExitWriteLock();
|
||||
}
|
||||
|
||||
while (!m_scriptsLock.TryEnterReadLock(60000))
|
||||
{
|
||||
m_log.Error("[XEngine.m_Scripts] Thread lock detected while trying to aquire READ lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
|
||||
if (m_scriptsLock.IsWriteLockHeld)
|
||||
{
|
||||
m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_scriptsLock.RecursiveReadCount > 0)
|
||||
{
|
||||
m_scriptsLock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
private void lockScriptsForWrite(bool locked)
|
||||
{
|
||||
if (locked)
|
||||
{
|
||||
if (m_scriptsLock.RecursiveReadCount > 0)
|
||||
{
|
||||
m_log.Error("[XEngine.m_Scripts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
|
||||
m_scriptsLock.ExitReadLock();
|
||||
}
|
||||
if (m_scriptsLock.RecursiveWriteCount > 0)
|
||||
{
|
||||
m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
|
||||
m_scriptsLock.ExitWriteLock();
|
||||
}
|
||||
|
||||
while (!m_scriptsLock.TryEnterWriteLock(60000))
|
||||
{
|
||||
m_log.Error("[XEngine.m_Scripts] Thread lock detected while trying to aquire WRITE lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
|
||||
if (m_scriptsLock.IsWriteLockHeld)
|
||||
{
|
||||
m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_scriptsLock.RecursiveWriteCount > 0)
|
||||
{
|
||||
m_scriptsLock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ScriptEngineConsoleCommands m_consoleCommands;
|
||||
|
||||
public string ScriptEngineName
|
||||
@@ -714,20 +782,31 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
{
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
lockScriptsForRead(true);
|
||||
|
||||
lock (m_Scripts)
|
||||
List<IScriptInstance> instancesToDel = new List<IScriptInstance>(m_Scripts.Values);
|
||||
|
||||
// foreach (IScriptInstance instance in m_Scripts.Values)
|
||||
foreach (IScriptInstance instance in instancesToDel)
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
"[XEngine]: Shutting down {0} scripts in {1}", m_Scripts.Count, m_Scene.RegionInfo.RegionName);
|
||||
|
||||
foreach (IScriptInstance instance in m_Scripts.Values)
|
||||
// Force a final state save
|
||||
//
|
||||
if (m_Assemblies.ContainsKey(instance.AssetID))
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
// Force a final state save
|
||||
//
|
||||
try
|
||||
{
|
||||
if (instance.StatePersistedHere)
|
||||
instance.SaveState();
|
||||
=======
|
||||
string assembly = m_Assemblies[instance.AssetID];
|
||||
|
||||
try
|
||||
{
|
||||
instance.SaveState(assembly);
|
||||
>>>>>>> avn/ubitvar
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -737,36 +816,50 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name)
|
||||
, e);
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
// Clear the event queue and abort the instance thread
|
||||
//
|
||||
instance.Stop(0, true);
|
||||
=======
|
||||
// Clear the event queue and abort the instance thread
|
||||
//
|
||||
instance.ClearQueue();
|
||||
instance.Stop(0);
|
||||
>>>>>>> avn/ubitvar
|
||||
|
||||
// Release events, timer, etc
|
||||
//
|
||||
instance.DestroyScriptInstance();
|
||||
// Release events, timer, etc
|
||||
//
|
||||
instance.DestroyScriptInstance();
|
||||
|
||||
// Unload scripts and app domains.
|
||||
// Must be done explicitly because they have infinite
|
||||
// lifetime.
|
||||
// However, don't bother to do this if the simulator is shutting
|
||||
// down since it takes a long time with many scripts.
|
||||
if (!m_SimulatorShuttingDown)
|
||||
// Unload scripts and app domains
|
||||
// Must be done explicitly because they have infinite
|
||||
// lifetime
|
||||
//
|
||||
// if (!m_SimulatorShuttingDown)
|
||||
{
|
||||
m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
|
||||
if (m_DomainScripts[instance.AppDomain].Count == 0)
|
||||
{
|
||||
m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
|
||||
if (m_DomainScripts[instance.AppDomain].Count == 0)
|
||||
{
|
||||
m_DomainScripts.Remove(instance.AppDomain);
|
||||
UnloadAppDomain(instance.AppDomain);
|
||||
}
|
||||
m_DomainScripts.Remove(instance.AppDomain);
|
||||
UnloadAppDomain(instance.AppDomain);
|
||||
}
|
||||
}
|
||||
|
||||
m_Scripts.Clear();
|
||||
m_PrimObjects.Clear();
|
||||
m_Assemblies.Clear();
|
||||
m_DomainScripts.Clear();
|
||||
// m_Scripts.Clear();
|
||||
// m_PrimObjects.Clear();
|
||||
// m_Assemblies.Clear();
|
||||
// m_DomainScripts.Clear();
|
||||
}
|
||||
lockScriptsForRead(false);
|
||||
lockScriptsForWrite(true);
|
||||
m_Scripts.Clear();
|
||||
lockScriptsForWrite(false);
|
||||
m_PrimObjects.Clear();
|
||||
m_Assemblies.Clear();
|
||||
m_DomainScripts.Clear();
|
||||
|
||||
lock (m_ScriptEngines)
|
||||
{
|
||||
m_ScriptEngines.Remove(this);
|
||||
@@ -835,6 +928,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
|
||||
List<IScriptInstance> instances = new List<IScriptInstance>();
|
||||
|
||||
<<<<<<< HEAD
|
||||
lock (m_Scripts)
|
||||
{
|
||||
foreach (IScriptInstance instance in m_Scripts.Values)
|
||||
@@ -852,6 +946,23 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
|
||||
foreach (IScriptInstance i in instances)
|
||||
{
|
||||
=======
|
||||
lockScriptsForRead(true);
|
||||
foreach (IScriptInstance instance in m_Scripts.Values)
|
||||
instances.Add(instance);
|
||||
lockScriptsForRead(false);
|
||||
|
||||
foreach (IScriptInstance i in instances)
|
||||
{
|
||||
string assembly = String.Empty;
|
||||
|
||||
|
||||
if (!m_Assemblies.ContainsKey(i.AssetID))
|
||||
continue;
|
||||
assembly = m_Assemblies[i.AssetID];
|
||||
|
||||
|
||||
>>>>>>> avn/ubitvar
|
||||
try
|
||||
{
|
||||
i.SaveState();
|
||||
@@ -1282,58 +1393,79 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
}
|
||||
|
||||
ScriptInstance instance = null;
|
||||
lock (m_Scripts)
|
||||
// Create the object record
|
||||
UUID appDomain = assetID;
|
||||
|
||||
|
||||
|
||||
lockScriptsForRead(true);
|
||||
if ((!m_Scripts.ContainsKey(itemID)) ||
|
||||
(m_Scripts[itemID].AssetID != assetID))
|
||||
{
|
||||
// Create the object record
|
||||
if ((!m_Scripts.ContainsKey(itemID)) ||
|
||||
(m_Scripts[itemID].AssetID != assetID))
|
||||
lockScriptsForRead(false);
|
||||
instance = new ScriptInstance(this, part,
|
||||
item,
|
||||
startParam, postOnRez,
|
||||
m_MaxScriptQueue);
|
||||
|
||||
if (part.ParentGroup.IsAttachment)
|
||||
appDomain = part.ParentGroup.RootPart.UUID;
|
||||
|
||||
if (!m_AppDomains.ContainsKey(appDomain))
|
||||
{
|
||||
UUID appDomain = assetID;
|
||||
|
||||
if (part.ParentGroup.IsAttachment)
|
||||
appDomain = part.ParentGroup.RootPart.UUID;
|
||||
|
||||
if (!m_AppDomains.ContainsKey(appDomain))
|
||||
try
|
||||
{
|
||||
try
|
||||
AppDomainSetup appSetup = new AppDomainSetup();
|
||||
appSetup.PrivateBinPath = Path.Combine(
|
||||
m_ScriptEnginesPath,
|
||||
m_Scene.RegionInfo.RegionID.ToString());
|
||||
|
||||
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
|
||||
Evidence evidence = new Evidence(baseEvidence);
|
||||
|
||||
AppDomain sandbox;
|
||||
if (m_AppDomainLoading)
|
||||
{
|
||||
AppDomainSetup appSetup = new AppDomainSetup();
|
||||
appSetup.PrivateBinPath = Path.Combine(
|
||||
m_ScriptEnginesPath,
|
||||
m_Scene.RegionInfo.RegionID.ToString());
|
||||
|
||||
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
|
||||
Evidence evidence = new Evidence(baseEvidence);
|
||||
|
||||
AppDomain sandbox;
|
||||
if (m_AppDomainLoading)
|
||||
sandbox = AppDomain.CreateDomain(
|
||||
m_Scene.RegionInfo.RegionID.ToString(),
|
||||
evidence, appSetup);
|
||||
if (m_AppDomains.ContainsKey(appDomain))
|
||||
{
|
||||
sandbox = AppDomain.CreateDomain(
|
||||
m_Scene.RegionInfo.RegionID.ToString(),
|
||||
evidence, appSetup);
|
||||
sandbox.AssemblyResolve +=
|
||||
m_AppDomains[appDomain].AssemblyResolve +=
|
||||
new ResolveEventHandler(
|
||||
AssemblyResolver.OnAssemblyResolve);
|
||||
if (m_DomainScripts.ContainsKey(appDomain))
|
||||
{
|
||||
m_DomainScripts[appDomain].Add(itemID);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_DomainScripts.Add(appDomain, new List<UUID>());
|
||||
m_DomainScripts[appDomain].Add(itemID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sandbox = AppDomain.CurrentDomain;
|
||||
}
|
||||
|
||||
//PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel();
|
||||
//AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition();
|
||||
//PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet");
|
||||
//PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet);
|
||||
//CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement);
|
||||
//sandboxPolicy.RootCodeGroup = sandboxCodeGroup;
|
||||
//sandbox.SetAppDomainPolicy(sandboxPolicy);
|
||||
|
||||
m_AppDomains[appDomain] = sandbox;
|
||||
m_AppDomains.Add(appDomain, sandbox);
|
||||
m_AppDomains[appDomain].AssemblyResolve +=
|
||||
new ResolveEventHandler(
|
||||
AssemblyResolver.OnAssemblyResolve);
|
||||
if (m_DomainScripts.ContainsKey(appDomain))
|
||||
{
|
||||
m_DomainScripts[appDomain].Add(itemID);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_DomainScripts.Add(appDomain, new List<UUID>());
|
||||
m_DomainScripts[appDomain].Add(itemID);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_DomainScripts[appDomain] = new List<UUID>();
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString());
|
||||
m_ScriptErrorMessage += "Exception creating app domain:\n";
|
||||
m_ScriptFailCount++;
|
||||
@@ -1342,10 +1474,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
m_AddingAssemblies[assemblyPath]--;
|
||||
}
|
||||
return false;
|
||||
=======
|
||||
sandbox = AppDomain.CurrentDomain;
|
||||
>>>>>>> avn/ubitvar
|
||||
}
|
||||
}
|
||||
m_DomainScripts[appDomain].Add(itemID);
|
||||
|
||||
<<<<<<< HEAD
|
||||
IScript scriptObj = null;
|
||||
EventWaitHandle coopSleepHandle;
|
||||
bool coopTerminationForThisScript;
|
||||
@@ -1477,26 +1611,52 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
scriptObj, coopSleepHandle, assemblyPath,
|
||||
Path.Combine(ScriptEnginePath, World.RegionInfo.RegionID.ToString()), stateSource, coopTerminationForThisScript))
|
||||
return false;
|
||||
=======
|
||||
// if (!instance.Load(m_AppDomains[appDomain], assembly, stateSource))
|
||||
// return false;
|
||||
>>>>>>> avn/ubitvar
|
||||
|
||||
// if (DebugLevel >= 1)
|
||||
// m_log.DebugFormat(
|
||||
// "[XEngine] Loaded script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}",
|
||||
// part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
|
||||
m_AppDomains[appDomain] = sandbox;
|
||||
|
||||
m_DomainScripts[appDomain] = new List<UUID>();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString());
|
||||
m_ScriptErrorMessage += "Exception creating app domain:\n";
|
||||
m_ScriptFailCount++;
|
||||
lock (m_AddingAssemblies)
|
||||
{
|
||||
m_AddingAssemblies[assembly]--;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!instance.Load(m_AppDomains[appDomain], assembly, stateSource))
|
||||
return false;
|
||||
// m_log.DebugFormat(
|
||||
// "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}",
|
||||
// part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID,
|
||||
// part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
|
||||
|
||||
if (presence != null)
|
||||
{
|
||||
ShowScriptSaveResponse(item.OwnerID,
|
||||
assetID, "Compile successful", true);
|
||||
}
|
||||
|
||||
instance.AppDomain = appDomain;
|
||||
instance.LineMap = linemap;
|
||||
|
||||
m_Scripts[itemID] = instance;
|
||||
if (presence != null)
|
||||
{
|
||||
ShowScriptSaveResponse(item.OwnerID,
|
||||
assetID, "Compile successful", true);
|
||||
}
|
||||
}
|
||||
|
||||
instance.AppDomain = appDomain;
|
||||
instance.LineMap = linemap;
|
||||
lockScriptsForWrite(true);
|
||||
m_Scripts[itemID] = instance;
|
||||
lockScriptsForWrite(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
lockScriptsForRead(false);
|
||||
}
|
||||
lock (m_PrimObjects)
|
||||
{
|
||||
if (!m_PrimObjects.ContainsKey(localID))
|
||||
@@ -1514,7 +1674,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
m_AddingAssemblies[assemblyPath]--;
|
||||
}
|
||||
|
||||
if (instance != null)
|
||||
if (instance!=null)
|
||||
instance.Init();
|
||||
|
||||
bool runIt;
|
||||
@@ -1537,19 +1697,28 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
m_CompileDict.Remove(itemID);
|
||||
}
|
||||
|
||||
IScriptInstance instance = null;
|
||||
|
||||
lock (m_Scripts)
|
||||
lockScriptsForRead(true);
|
||||
// Do we even have it?
|
||||
if (!m_Scripts.ContainsKey(itemID))
|
||||
{
|
||||
// Do we even have it?
|
||||
if (!m_Scripts.ContainsKey(itemID))
|
||||
return;
|
||||
|
||||
instance = m_Scripts[itemID];
|
||||
m_Scripts.Remove(itemID);
|
||||
}
|
||||
lockScriptsForRead(false);
|
||||
return;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
instance.Stop(m_WaitForEventCompletionOnScriptStop, true);
|
||||
=======
|
||||
IScriptInstance instance=m_Scripts[itemID];
|
||||
lockScriptsForRead(false);
|
||||
lockScriptsForWrite(true);
|
||||
m_Scripts.Remove(itemID);
|
||||
lockScriptsForWrite(false);
|
||||
instance.ClearQueue();
|
||||
|
||||
instance.Stop(m_WaitForEventCompletionOnScriptStop);
|
||||
|
||||
// bool objectRemoved = false;
|
||||
>>>>>>> avn/ubitvar
|
||||
|
||||
lock (m_PrimObjects)
|
||||
{
|
||||
@@ -1571,17 +1740,26 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
|
||||
instance.DestroyScriptInstance();
|
||||
|
||||
m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
|
||||
if (m_DomainScripts[instance.AppDomain].Count == 0)
|
||||
if (m_DomainScripts.ContainsKey(instance.AppDomain))
|
||||
{
|
||||
m_DomainScripts.Remove(instance.AppDomain);
|
||||
UnloadAppDomain(instance.AppDomain);
|
||||
m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
|
||||
if (m_DomainScripts[instance.AppDomain].Count == 0)
|
||||
{
|
||||
m_DomainScripts.Remove(instance.AppDomain);
|
||||
UnloadAppDomain(instance.AppDomain);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectRemoved handlerObjectRemoved = OnObjectRemoved;
|
||||
if (handlerObjectRemoved != null)
|
||||
handlerObjectRemoved(instance.ObjectID);
|
||||
{
|
||||
SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
|
||||
if (part != null)
|
||||
handlerObjectRemoved(part.UUID);
|
||||
}
|
||||
|
||||
CleanAssemblies();
|
||||
|
||||
ScriptRemoved handlerScriptRemoved = OnScriptRemoved;
|
||||
if (handlerScriptRemoved != null)
|
||||
handlerScriptRemoved(itemID);
|
||||
@@ -1842,12 +2020,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
private IScriptInstance GetInstance(UUID itemID)
|
||||
{
|
||||
IScriptInstance instance;
|
||||
lock (m_Scripts)
|
||||
lockScriptsForRead(true);
|
||||
if (!m_Scripts.ContainsKey(itemID))
|
||||
{
|
||||
if (!m_Scripts.ContainsKey(itemID))
|
||||
return null;
|
||||
instance = m_Scripts[itemID];
|
||||
lockScriptsForRead(false);
|
||||
return null;
|
||||
}
|
||||
instance = m_Scripts[itemID];
|
||||
lockScriptsForRead(false);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -1869,6 +2049,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
return instance != null && instance.Running;
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
public void ApiResetScript(UUID itemID)
|
||||
{
|
||||
IScriptInstance instance = GetInstance(itemID);
|
||||
@@ -1953,6 +2134,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
return instance != null ? instance.GetDetectID(idx) : UUID.Zero;
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
public void SetState(UUID itemID, string newState)
|
||||
{
|
||||
IScriptInstance instance = GetInstance(itemID);
|
||||
@@ -1973,11 +2155,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||
|
||||
List<IScriptInstance> instances = new List<IScriptInstance>();
|
||||
|
||||
lock (m_Scripts)
|
||||
{
|
||||
foreach (IScriptInstance instance in m_Scripts.Values)
|
||||
lockScriptsForRead(true);
|
||||
foreach (IScriptInstance instance in m_Scripts.Values)
|
||||
instances.Add(instance);
|
||||
}
|
||||
lockScriptsForRead(false);
|
||||
|
||||
foreach (IScriptInstance i in instances)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user