2008-08-27 22:38:36 +00:00
/ *
* 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 .
2009-06-01 06:37:14 +00:00
* * Neither the name of the OpenSimulator Project nor the
2008-08-27 22:38:36 +00:00
* 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 ;
2012-07-11 21:54:22 +00:00
using System.Collections ;
using System.Collections.Generic ;
using System.Globalization ;
2008-08-27 22:38:36 +00:00
using System.IO ;
2012-07-11 21:54:22 +00:00
using System.Reflection ;
2008-11-26 11:12:57 +00:00
using System.Runtime.Remoting ;
using System.Runtime.Remoting.Lifetime ;
2008-08-27 22:38:36 +00:00
using System.Security.Policy ;
2012-07-11 21:54:22 +00:00
using System.Text ;
using System.Threading ;
2008-08-27 22:38:36 +00:00
using System.Xml ;
2008-09-06 07:52:41 +00:00
using OpenMetaverse ;
2008-10-11 16:32:31 +00:00
using log4net ;
2008-08-27 22:38:36 +00:00
using Nini.Config ;
using Amib.Threading ;
using OpenSim.Framework ;
2009-02-10 13:10:57 +00:00
using OpenSim.Region.CoreModules ;
2009-02-06 16:55:34 +00:00
using OpenSim.Region.Framework.Scenes ;
using OpenSim.Region.Framework.Interfaces ;
2008-08-27 22:38:36 +00:00
using OpenSim.Region.ScriptEngine.Shared ;
using OpenSim.Region.ScriptEngine.Shared.Api ;
2008-11-26 11:12:57 +00:00
using OpenSim.Region.ScriptEngine.Shared.Api.Runtime ;
2008-08-27 22:38:36 +00:00
using OpenSim.Region.ScriptEngine.Shared.ScriptBase ;
using OpenSim.Region.ScriptEngine.Shared.CodeTools ;
using OpenSim.Region.ScriptEngine.Interfaces ;
namespace OpenSim.Region.ScriptEngine.Shared.Instance
{
2009-08-14 13:18:56 +00:00
public class ScriptInstance : MarshalByRefObject , IScriptInstance
2008-08-27 22:38:36 +00:00
{
2012-01-26 00:28:51 +00:00
private static readonly ILog m_log = LogManager . GetLogger ( MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2012-03-14 00:29:36 +00:00
2015-01-16 22:44:54 +00:00
public bool StatePersistedHere { get { return m_AttachedAvatar = = UUID . Zero ; } }
2012-03-14 00:29:36 +00:00
/// <summary>
/// The current work item if an event for this script is running or waiting to run,
/// </summary>
/// <remarks>
2012-03-15 02:02:31 +00:00
/// Null if there is no running or waiting to run event. Must be changed only under an EventQueue lock.
2012-03-14 00:29:36 +00:00
/// </remarks>
private IScriptWorkItem m_CurrentWorkItem ;
2008-08-27 22:38:36 +00:00
private IScript m_Script ;
private DetectParams [ ] m_DetectParams ;
private bool m_TimerQueued ;
private DateTime m_EventStart ;
private bool m_InEvent ;
2014-12-10 00:25:27 +00:00
private string m_assemblyPath ;
private string m_dataPath ;
2008-08-27 22:38:36 +00:00
private string m_CurrentEvent = String . Empty ;
2009-10-29 13:42:40 +00:00
private bool m_InSelfDelete ;
2008-08-27 22:53:58 +00:00
private int m_MaxScriptQueue ;
2015-01-16 22:44:54 +00:00
private bool m_SaveState ;
2009-10-29 13:42:40 +00:00
private int m_ControlEventsInQueue ;
private int m_LastControlLevel ;
private bool m_CollisionInQueue ;
2012-03-15 02:02:31 +00:00
2008-12-21 19:04:06 +00:00
// The following is for setting a minimum delay between events
2009-10-29 13:42:40 +00:00
private double m_minEventDelay ;
2012-03-15 02:02:31 +00:00
2009-10-29 13:42:40 +00:00
private long m_eventDelayTicks ;
private long m_nextEventTimeTicks ;
2009-01-28 09:52:09 +00:00
private bool m_startOnInit = true ;
2009-10-29 13:42:40 +00:00
private UUID m_AttachedAvatar ;
2009-01-28 09:52:09 +00:00
private StateSource m_stateSource ;
private bool m_postOnRez ;
2009-10-29 13:42:40 +00:00
private bool m_startedFromSavedState ;
2009-10-29 12:56:37 +00:00
private UUID m_CurrentStateHash ;
2009-10-29 13:42:40 +00:00
private UUID m_RegionID ;
2008-12-21 13:28:51 +00:00
2012-12-12 23:13:34 +00:00
public int DebugLevel { get ; set ; }
2012-03-15 02:02:31 +00:00
public Dictionary < KeyValuePair < int , int > , KeyValuePair < int , int > > LineMap { get ; set ; }
2008-08-27 22:38:36 +00:00
private Dictionary < string , IScriptApi > m_Apis = new Dictionary < string , IScriptApi > ( ) ;
public Object [ ] PluginData = new Object [ 0 ] ;
2008-12-21 19:04:06 +00:00
/// <summary>
/// Used by llMinEventDelay to suppress events happening any faster than this speed.
/// This currently restricts all events in one go. Not sure if each event type has
/// its own check so take the simple route first.
/// </summary>
public double MinEventDelay
{
get { return m_minEventDelay ; }
set
{
if ( value > 0.001 )
m_minEventDelay = value ;
else
m_minEventDelay = 0.0 ;
2012-01-26 00:28:51 +00:00
2008-12-21 19:04:06 +00:00
m_eventDelayTicks = ( long ) ( m_minEventDelay * 10000000L ) ;
m_nextEventTimeTicks = DateTime . Now . Ticks ;
}
}
2012-03-15 00:48:19 +00:00
public bool Running { get ; set ; }
2008-08-27 22:38:36 +00:00
2011-10-19 20:30:37 +00:00
public bool Suspended
{
get { return m_Suspended ; }
set
{
// Need to do this inside a lock in order to avoid races with EventProcessor()
lock ( m_Script )
{
bool wasSuspended = m_Suspended ;
m_Suspended = value ;
if ( wasSuspended & & ! m_Suspended )
{
2012-03-15 02:02:31 +00:00
lock ( EventQueue )
2011-10-19 20:30:37 +00:00
{
// Need to place ourselves back in a work item if there are events to process
2012-03-15 02:02:31 +00:00
if ( EventQueue . Count > 0 & & Running & & ! ShuttingDown )
m_CurrentWorkItem = Engine . QueueEventHandler ( this ) ;
2011-10-19 20:30:37 +00:00
}
}
}
}
}
private bool m_Suspended ;
2011-10-19 19:24:07 +00:00
2012-03-15 02:02:31 +00:00
public bool ShuttingDown { get ; set ; }
2008-09-08 02:40:20 +00:00
2012-03-15 02:02:31 +00:00
public string State { get ; set ; }
2008-08-27 22:38:36 +00:00
2012-03-15 02:02:31 +00:00
public IScriptEngine Engine { get ; private set ; }
2008-08-27 22:38:36 +00:00
2012-03-15 02:02:31 +00:00
public UUID AppDomain { get ; set ; }
2008-08-27 22:38:36 +00:00
2013-01-14 23:19:47 +00:00
public SceneObjectPart Part { get ; private set ; }
2012-03-15 02:02:31 +00:00
public string PrimName { get ; private set ; }
2008-08-27 22:38:36 +00:00
2012-03-15 02:02:31 +00:00
public string ScriptName { get ; private set ; }
2008-08-27 22:38:36 +00:00
2012-03-15 02:02:31 +00:00
public UUID ItemID { get ; private set ; }
2008-08-27 22:38:36 +00:00
2013-01-14 23:19:47 +00:00
public UUID ObjectID { get { return Part . UUID ; } }
2008-08-27 22:38:36 +00:00
2013-01-14 23:19:47 +00:00
public uint LocalID { get { return Part . LocalId ; } }
2008-08-27 22:38:36 +00:00
2013-01-14 23:19:47 +00:00
public UUID RootObjectID { get { return Part . ParentGroup . UUID ; } }
2012-03-16 01:31:53 +00:00
2013-01-14 23:19:47 +00:00
public uint RootLocalID { get { return Part . ParentGroup . LocalId ; } }
2012-03-16 01:31:53 +00:00
2012-03-15 02:02:31 +00:00
public UUID AssetID { get ; private set ; }
2008-08-27 22:38:36 +00:00
2012-03-15 02:02:31 +00:00
public Queue EventQueue { get ; private set ; }
2008-08-27 22:38:36 +00:00
2012-12-05 23:33:48 +00:00
public long EventsQueued
{
get
{
lock ( EventQueue )
return EventQueue . Count ;
}
}
2012-12-05 22:33:28 +00:00
public long EventsProcessed { get ; private set ; }
2012-03-15 02:02:31 +00:00
public int StartParam { get ; set ; }
2008-08-27 22:38:36 +00:00
2012-03-15 02:02:31 +00:00
public TaskInventoryItem ScriptTask { get ; private set ; }
2008-08-27 22:38:36 +00:00
2012-03-16 00:34:30 +00:00
public DateTime TimeStarted { get ; private set ; }
public long MeasurementPeriodTickStart { get ; private set ; }
public long MeasurementPeriodExecutionTime { get ; private set ; }
public static readonly long MaxMeasurementPeriod = 30 * TimeSpan . TicksPerMinute ;
2013-01-16 02:07:43 +00:00
private bool m_coopTermination ;
private EventWaitHandle m_coopSleepHandle ;
2012-03-15 02:02:31 +00:00
public void ClearQueue ( )
2008-12-21 13:28:51 +00:00
{
2012-03-15 02:02:31 +00:00
m_TimerQueued = false ;
EventQueue . Clear ( ) ;
2008-12-21 13:28:51 +00:00
}
2013-01-15 21:13:22 +00:00
public ScriptInstance (
IScriptEngine engine , SceneObjectPart part , TaskInventoryItem item ,
int startParam , bool postOnRez ,
int maxScriptQueue )
2008-08-27 22:38:36 +00:00
{
2012-03-15 02:02:31 +00:00
State = "default" ;
EventQueue = new Queue ( 32 ) ;
Engine = engine ;
2013-01-14 23:19:47 +00:00
Part = part ;
2013-01-15 21:13:22 +00:00
ScriptTask = item ;
// This is currently only here to allow regression tests to get away without specifying any inventory
// item when they are testing script logic that doesn't require an item.
if ( ScriptTask ! = null )
{
ScriptName = ScriptTask . Name ;
ItemID = ScriptTask . ItemID ;
AssetID = ScriptTask . AssetID ;
}
PrimName = part . ParentGroup . Name ;
2012-03-15 02:02:31 +00:00
StartParam = startParam ;
2008-08-27 22:53:58 +00:00
m_MaxScriptQueue = maxScriptQueue ;
2009-01-28 09:52:09 +00:00
m_postOnRez = postOnRez ;
2013-01-14 23:19:47 +00:00
m_AttachedAvatar = Part . ParentGroup . AttachedAvatar ;
m_RegionID = Part . ParentGroup . Scene . RegionInfo . RegionID ;
2015-01-16 22:44:54 +00:00
m_SaveState = StatePersistedHere ;
// m_log.DebugFormat(
// "[SCRIPT INSTANCE]: Instantiated script instance {0} (id {1}) in part {2} (id {3}) in object {4} attached avatar {5} in {6}",
// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, m_AttachedAvatar, Engine.World.Name);
2013-01-15 21:13:22 +00:00
}
2008-08-27 22:38:36 +00:00
2013-01-15 21:13:22 +00:00
/// <summary>
/// Load the script from an assembly into an AppDomain.
/// </summary>
/// <param name='dom'></param>
/// <param name='assembly'></param>
2014-12-10 00:25:27 +00:00
/// <param name='dataPath'>
/// Path for all script associated data (state, etc.). In a multi-region set up
/// with all scripts loading into the same AppDomain this may not be the same place as the DLL itself.
/// </param>
2013-01-15 21:13:22 +00:00
/// <param name='stateSource'></param>
2013-01-23 02:28:27 +00:00
/// <returns>false if load failed, true if suceeded</returns>
2014-12-10 00:25:27 +00:00
public bool Load ( AppDomain dom , Assembly scriptAssembly , string dataPath , StateSource stateSource )
2013-01-15 21:13:22 +00:00
{
2014-12-10 00:25:27 +00:00
m_assemblyPath = scriptAssembly . Location ;
m_dataPath = dataPath ;
2013-01-15 21:13:22 +00:00
m_stateSource = stateSource ;
2012-03-15 01:26:38 +00:00
try
{
2013-01-23 02:28:27 +00:00
object [ ] constructorParams ;
Type scriptType = scriptAssembly . GetType ( "SecondLife.XEngineScript" ) ;
if ( scriptType ! = null )
{
2014-07-10 23:03:02 +00:00
m_coopTermination = true ;
m_coopSleepHandle = new XEngineEventWaitHandle ( false , EventResetMode . AutoReset ) ;
2013-01-23 02:28:27 +00:00
constructorParams = new object [ ] { m_coopSleepHandle } ;
}
2014-07-10 23:03:02 +00:00
else
2013-01-23 02:28:27 +00:00
{
2014-07-10 23:03:02 +00:00
m_coopTermination = false ;
2013-01-23 02:28:27 +00:00
scriptType = scriptAssembly . GetType ( "SecondLife.Script" ) ;
constructorParams = null ;
}
2012-03-15 01:26:38 +00:00
if ( dom ! = System . AppDomain . CurrentDomain )
2013-01-17 23:39:09 +00:00
m_Script
= ( IScript ) dom . CreateInstanceAndUnwrap (
2014-12-10 00:25:27 +00:00
Path . GetFileNameWithoutExtension ( m_assemblyPath ) ,
2013-01-23 02:28:27 +00:00
scriptType . FullName ,
2013-01-17 23:39:09 +00:00
false ,
BindingFlags . Default ,
null ,
2013-01-23 02:28:27 +00:00
constructorParams ,
2013-01-17 23:39:09 +00:00
null ,
2013-01-24 00:23:12 +00:00
null ,
2013-01-17 23:39:09 +00:00
null ) ;
2012-03-15 01:26:38 +00:00
else
2013-01-17 23:39:09 +00:00
m_Script
2013-01-23 02:28:27 +00:00
= ( IScript ) scriptAssembly . CreateInstance (
scriptType . FullName ,
2013-01-17 23:39:09 +00:00
false ,
BindingFlags . Default ,
null ,
2013-01-23 02:28:27 +00:00
constructorParams ,
2013-01-17 23:39:09 +00:00
null ,
null ) ;
2008-11-26 11:12:57 +00:00
2009-09-06 19:17:30 +00:00
//ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
2009-10-26 14:50:25 +00:00
//RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
2009-08-14 13:27:56 +00:00
// lease.Register(this);
2008-08-27 22:38:36 +00:00
}
2012-01-26 00:28:51 +00:00
catch ( Exception e )
2008-08-27 22:38:36 +00:00
{
2012-01-26 00:28:51 +00:00
m_log . ErrorFormat (
2013-01-23 23:34:15 +00:00
"[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error loading assembly {6}. Exception {7}{8}" ,
2014-12-10 00:25:27 +00:00
ScriptTask . Name , ScriptTask . ItemID , Part . Name , Part . UUID , Part . ParentGroup . Name , Engine . World . Name , scriptAssembly . Location , e . Message , e . StackTrace ) ;
2013-01-23 02:28:27 +00:00
return false ;
2008-08-27 22:38:36 +00:00
}
2014-07-10 23:03:02 +00:00
ApiManager am = new ApiManager ( ) ;
foreach ( string api in am . GetApis ( ) )
{
m_Apis [ api ] = am . CreateApi ( api ) ;
m_Apis [ api ] . Initialize ( Engine , Part , ScriptTask , m_coopSleepHandle ) ;
}
2008-08-27 22:38:36 +00:00
try
{
foreach ( KeyValuePair < string , IScriptApi > kv in m_Apis )
{
m_Script . InitApi ( kv . Key , kv . Value ) ;
}
2009-05-18 15:32:06 +00:00
// // m_log.Debug("[Script] Script instance created");
2008-08-27 22:38:36 +00:00
2014-07-10 23:03:02 +00:00
Part . SetScriptEvents ( ItemID , ( int ) m_Script . GetStateEventFlags ( State ) ) ;
2008-08-27 22:38:36 +00:00
}
2012-01-26 00:28:51 +00:00
catch ( Exception e )
2008-08-27 22:38:36 +00:00
{
2012-01-26 00:28:51 +00:00
m_log . ErrorFormat (
2013-01-23 23:34:15 +00:00
"[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error initializing script instance. Exception {6}{7}" ,
ScriptTask . Name , ScriptTask . ItemID , Part . Name , Part . UUID , Part . ParentGroup . Name , Engine . World . Name , e . Message , e . StackTrace ) ;
2012-01-26 00:28:51 +00:00
2013-01-23 02:28:27 +00:00
return false ;
2008-08-27 22:38:36 +00:00
}
2015-01-16 22:44:54 +00:00
// For attachments, XEngine saves the state into a .state file when XEngine.SetXMLState() is called.
2014-12-10 00:25:27 +00:00
string savedState = Path . Combine ( m_dataPath , ItemID . ToString ( ) + ".state" ) ;
2014-07-10 23:03:02 +00:00
2008-08-27 22:38:36 +00:00
if ( File . Exists ( savedState ) )
{
2014-12-10 00:25:27 +00:00
// m_log.DebugFormat(
// "[SCRIPT INSTANCE]: Found state for script {0} for {1} ({2}) at {3} in {4}",
// ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name);
2008-08-27 22:38:36 +00:00
string xml = String . Empty ;
try
{
FileInfo fi = new FileInfo ( savedState ) ;
2009-09-14 14:14:59 +00:00
int size = ( int ) fi . Length ;
2008-08-27 22:38:36 +00:00
if ( size < 512000 )
{
using ( FileStream fs = File . Open ( savedState ,
FileMode . Open , FileAccess . Read , FileShare . None ) )
{
Byte [ ] data = new Byte [ size ] ;
fs . Read ( data , 0 , size ) ;
2012-07-11 21:54:22 +00:00
xml = Encoding . UTF8 . GetString ( data ) ;
2008-08-27 22:38:36 +00:00
ScriptSerializer . Deserialize ( xml , this ) ;
2012-03-15 02:02:31 +00:00
AsyncCommandManager . CreateFromData ( Engine ,
LocalID , ItemID , ObjectID ,
2008-08-27 22:38:36 +00:00
PluginData ) ;
2012-03-15 02:02:31 +00:00
// m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName);
2008-08-27 22:38:36 +00:00
2013-01-14 23:19:47 +00:00
Part . SetScriptEvents ( ItemID ,
2008-09-08 22:19:06 +00:00
( int ) m_Script . GetStateEventFlags ( State ) ) ;
2012-07-17 13:00:42 +00:00
if ( ! Running )
2009-01-28 09:52:09 +00:00
m_startOnInit = false ;
2008-08-27 22:38:36 +00:00
2012-07-17 13:00:42 +00:00
Running = false ;
2008-08-27 22:38:36 +00:00
// we get new rez events on sim restart, too
// but if there is state, then we fire the change
// event
2008-09-07 22:01:25 +00:00
// We loaded state, don't force a re-save
m_SaveState = false ;
2009-01-28 09:52:09 +00:00
m_startedFromSavedState = true ;
2008-08-27 22:38:36 +00:00
}
2015-01-16 22:44:54 +00:00
// If this script is in an attachment then we no longer need the state file.
if ( ! StatePersistedHere )
RemoveState ( ) ;
2008-08-27 22:38:36 +00:00
}
2014-12-10 00:25:27 +00:00
// else
// {
// m_log.WarnFormat(
// "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.",
// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState);
// }
2008-08-27 22:38:36 +00:00
}
2012-01-26 00:28:51 +00:00
catch ( Exception e )
2008-08-27 22:38:36 +00:00
{
2012-01-26 00:28:51 +00:00
m_log . ErrorFormat (
2013-01-23 23:34:15 +00:00
"[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}" ,
ScriptTask . Name , ScriptTask . ItemID , Part . Name , Part . UUID , Part . ParentGroup . Name , Engine . World . Name , savedState , xml , e . Message , e . StackTrace ) ;
2008-08-27 22:38:36 +00:00
}
}
2009-10-17 21:36:44 +00:00
// else
// {
2014-12-10 00:25:27 +00:00
// m_log.DebugFormat(
// "[SCRIPT INSTANCE]: Did not find state for script {0} for {1} ({2}) at {3} in {4}",
// ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name);
2009-10-17 21:36:44 +00:00
// }
2013-01-23 02:28:27 +00:00
return true ;
2009-01-28 09:52:09 +00:00
}
public void Init ( )
{
2012-07-17 13:00:42 +00:00
if ( ShuttingDown )
2012-06-21 01:13:03 +00:00
return ;
2009-01-28 09:52:09 +00:00
if ( m_startedFromSavedState )
{
2012-07-17 13:00:42 +00:00
if ( m_startOnInit )
Start ( ) ;
2009-01-28 09:52:09 +00:00
if ( m_postOnRez )
{
PostEvent ( new EventParams ( "on_rez" ,
2012-03-15 02:02:31 +00:00
new Object [ ] { new LSL_Types . LSLInteger ( StartParam ) } , new DetectParams [ 0 ] ) ) ;
2009-01-28 09:52:09 +00:00
}
2008-08-27 22:38:36 +00:00
2009-08-04 03:07:12 +00:00
if ( m_stateSource = = StateSource . AttachedRez )
2009-08-04 01:43:08 +00:00
{
PostEvent ( new EventParams ( "attach" ,
2009-08-04 03:07:12 +00:00
new object [ ] { new LSL_Types . LSLString ( m_AttachedAvatar . ToString ( ) ) } , new DetectParams [ 0 ] ) ) ;
2009-08-04 01:43:08 +00:00
}
2010-08-06 13:33:22 +00:00
else if ( m_stateSource = = StateSource . RegionStart )
2009-01-28 09:52:09 +00:00
{
2010-11-26 21:46:48 +00:00
//m_log.Debug("[Script] Posted changed(CHANGED_REGION_RESTART) to script");
2009-01-28 09:52:09 +00:00
PostEvent ( new EventParams ( "changed" ,
2010-11-26 21:46:48 +00:00
new Object [ ] { new LSL_Types . LSLInteger ( ( int ) Changed . REGION_RESTART ) } , new DetectParams [ 0 ] ) ) ;
2009-01-28 09:52:09 +00:00
}
2010-11-26 21:46:48 +00:00
else if ( m_stateSource = = StateSource . PrimCrossing | | m_stateSource = = StateSource . Teleporting )
2009-01-28 09:52:09 +00:00
{
// CHANGED_REGION
PostEvent ( new EventParams ( "changed" ,
2010-11-26 21:46:48 +00:00
new Object [ ] { new LSL_Types . LSLInteger ( ( int ) Changed . REGION ) } , new DetectParams [ 0 ] ) ) ;
// CHANGED_TELEPORT
if ( m_stateSource = = StateSource . Teleporting )
PostEvent ( new EventParams ( "changed" ,
new Object [ ] { new LSL_Types . LSLInteger ( ( int ) Changed . TELEPORT ) } , new DetectParams [ 0 ] ) ) ;
2009-01-28 09:52:09 +00:00
}
2010-11-26 21:46:48 +00:00
}
2009-01-28 09:52:09 +00:00
else
{
2012-07-17 13:00:42 +00:00
if ( m_startOnInit )
Start ( ) ;
2009-01-28 09:52:09 +00:00
PostEvent ( new EventParams ( "state_entry" ,
new Object [ 0 ] , new DetectParams [ 0 ] ) ) ;
if ( m_postOnRez )
{
2008-08-27 22:38:36 +00:00
PostEvent ( new EventParams ( "on_rez" ,
2012-03-15 02:02:31 +00:00
new Object [ ] { new LSL_Types . LSLInteger ( StartParam ) } , new DetectParams [ 0 ] ) ) ;
2009-01-28 09:52:09 +00:00
}
2009-08-04 03:07:12 +00:00
if ( m_stateSource = = StateSource . AttachedRez )
2009-08-04 01:43:08 +00:00
{
PostEvent ( new EventParams ( "attach" ,
2009-08-04 03:07:12 +00:00
new object [ ] { new LSL_Types . LSLString ( m_AttachedAvatar . ToString ( ) ) } , new DetectParams [ 0 ] ) ) ;
2009-08-04 01:43:08 +00:00
}
2008-08-27 22:38:36 +00:00
}
}
2008-09-17 22:00:56 +00:00
private void ReleaseControls ( )
{
2013-01-14 23:19:47 +00:00
int permsMask ;
UUID permsGranter ;
lock ( Part . TaskInventory )
2008-09-17 22:00:56 +00:00
{
2013-01-14 23:19:47 +00:00
if ( ! Part . TaskInventory . ContainsKey ( ItemID ) )
return ;
2009-02-20 14:04:29 +00:00
2013-01-14 23:19:47 +00:00
permsGranter = Part . TaskInventory [ ItemID ] . PermsGranter ;
permsMask = Part . TaskInventory [ ItemID ] . PermsMask ;
}
2008-09-17 22:00:56 +00:00
2013-01-14 23:19:47 +00:00
if ( ( permsMask & ScriptBaseClass . PERMISSION_TAKE_CONTROLS ) ! = 0 )
{
ScenePresence presence = Engine . World . GetScenePresence ( permsGranter ) ;
if ( presence ! = null )
presence . UnRegisterControlEventsToScript ( LocalID , ItemID ) ;
2008-09-17 22:00:56 +00:00
}
}
public void DestroyScriptInstance ( )
{
ReleaseControls ( ) ;
2012-03-15 02:02:31 +00:00
AsyncCommandManager . RemoveScript ( Engine , LocalID , ItemID ) ;
2008-09-17 22:00:56 +00:00
}
2008-08-27 22:38:36 +00:00
public void RemoveState ( )
{
2014-12-10 00:25:27 +00:00
string savedState = Path . Combine ( m_dataPath , ItemID . ToString ( ) + ".state" ) ;
// m_log.DebugFormat(
// "[SCRIPT INSTANCE]: Deleting state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}.",
// savedState, ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
2008-08-27 22:38:36 +00:00
try
{
File . Delete ( savedState ) ;
}
2013-04-09 22:02:11 +00:00
catch ( Exception e )
2008-08-27 22:38:36 +00:00
{
2013-04-09 22:02:11 +00:00
m_log . Warn (
string . Format (
"[SCRIPT INSTANCE]: Could not delete script state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}. Exception " ,
2013-08-13 18:49:09 +00:00
savedState , ScriptTask . Name , ScriptTask . ItemID , Part . Name , Part . UUID , Part . ParentGroup . Name , Engine . World . Name ) ,
2013-04-09 22:02:11 +00:00
e ) ;
2008-08-27 22:38:36 +00:00
}
}
public void VarDump ( Dictionary < string , object > vars )
{
2012-03-15 02:02:31 +00:00
// m_log.Info("Variable dump for script "+ ItemID.ToString());
2009-05-22 14:57:00 +00:00
// foreach (KeyValuePair<string, object> v in vars)
// {
2009-05-18 15:32:06 +00:00
// m_log.Info("Variable: "+v.Key+" = "+v.Value.ToString());
2009-05-22 14:57:00 +00:00
// }
2008-08-27 22:38:36 +00:00
}
public void Start ( )
{
2012-03-15 02:02:31 +00:00
lock ( EventQueue )
2008-08-27 22:38:36 +00:00
{
if ( Running )
return ;
2012-03-15 00:48:19 +00:00
Running = true ;
2008-08-27 22:38:36 +00:00
2012-03-16 00:34:30 +00:00
TimeStarted = DateTime . Now ;
MeasurementPeriodTickStart = Util . EnvironmentTickCount ( ) ;
MeasurementPeriodExecutionTime = 0 ;
2012-03-15 02:02:31 +00:00
if ( EventQueue . Count > 0 )
2008-08-27 22:38:36 +00:00
{
2012-03-14 00:29:36 +00:00
if ( m_CurrentWorkItem = = null )
2012-03-15 02:02:31 +00:00
m_CurrentWorkItem = Engine . QueueEventHandler ( this ) ;
2009-05-18 15:32:06 +00:00
// else
// m_log.Error("[Script] Tried to start a script that was already queued");
2008-08-27 22:38:36 +00:00
}
}
}
public bool Stop ( int timeout )
{
2013-05-01 18:01:43 +00:00
if ( DebugLevel > = 1 )
m_log . DebugFormat (
"[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}" ,
ScriptName , ItemID , PrimName , ObjectID , timeout , m_InSelfDelete , DateTime . Now . Ticks ) ;
2012-02-09 00:10:45 +00:00
2012-03-14 00:29:36 +00:00
IScriptWorkItem workItem ;
2008-08-27 22:38:36 +00:00
2012-03-15 02:02:31 +00:00
lock ( EventQueue )
2008-08-27 22:38:36 +00:00
{
if ( ! Running )
return true ;
2012-03-14 00:29:36 +00:00
// If we're not running or waiting to run an event then we can safely stop.
if ( m_CurrentWorkItem = = null )
2008-08-27 22:38:36 +00:00
{
2012-03-15 00:48:19 +00:00
Running = false ;
2008-08-27 22:38:36 +00:00
return true ;
}
2012-03-14 00:29:36 +00:00
// If we are waiting to run an event then we can try to cancel it.
if ( m_CurrentWorkItem . Cancel ( ) )
2008-08-27 22:38:36 +00:00
{
2012-03-14 00:29:36 +00:00
m_CurrentWorkItem = null ;
2012-03-15 00:48:19 +00:00
Running = false ;
2008-08-27 22:38:36 +00:00
return true ;
}
2012-03-14 00:29:36 +00:00
workItem = m_CurrentWorkItem ;
2012-03-15 00:48:19 +00:00
Running = false ;
2008-08-27 22:38:36 +00:00
}
2012-03-14 00:29:36 +00:00
// Wait for the current event to complete.
2013-01-16 02:07:43 +00:00
if ( ! m_InSelfDelete )
2008-08-27 22:38:36 +00:00
{
2013-01-16 02:07:43 +00:00
if ( ! m_coopTermination )
{
// If we're not co-operative terminating then try and wait for the event to complete before stopping
2013-02-12 21:34:12 +00:00
if ( workItem . Wait ( timeout ) )
2013-01-16 02:07:43 +00:00
return true ;
}
else
{
2013-01-23 23:34:15 +00:00
if ( DebugLevel > = 1 )
m_log . DebugFormat (
"[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}" ,
ScriptName , ItemID , PrimName , ObjectID ) ;
2013-01-16 02:07:43 +00:00
// This will terminate the event on next handle check by the script.
m_coopSleepHandle . Set ( ) ;
// For now, we will wait forever since the event should always cleanly terminate once LSL loop
// checking is implemented. May want to allow a shorter timeout option later.
2013-02-12 21:34:12 +00:00
if ( workItem . Wait ( Timeout . Infinite ) )
2013-01-16 02:07:43 +00:00
{
2013-01-23 23:34:15 +00:00
if ( DebugLevel > = 1 )
m_log . DebugFormat (
"[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}" ,
ScriptName , ItemID , PrimName , ObjectID ) ;
2013-01-16 02:07:43 +00:00
return true ;
}
}
2008-08-27 22:38:36 +00:00
}
2012-03-15 02:02:31 +00:00
lock ( EventQueue )
2008-08-27 22:38:36 +00:00
{
2012-03-14 00:29:36 +00:00
workItem = m_CurrentWorkItem ;
2008-08-27 22:38:36 +00:00
}
2012-03-14 00:29:36 +00:00
if ( workItem = = null )
2008-08-27 22:38:36 +00:00
return true ;
2012-03-14 00:29:36 +00:00
// If the event still hasn't stopped and we the stop isn't the result of script or object removal, then
// forcibly abort the work item (this aborts the underlying thread).
2013-01-16 02:07:43 +00:00
// Co-operative termination should never reach this point.
2008-08-27 22:38:36 +00:00
if ( ! m_InSelfDelete )
2012-03-12 21:16:05 +00:00
{
2012-12-12 23:30:26 +00:00
m_log . DebugFormat (
"[SCRIPT INSTANCE]: Aborting unstopped script {0} {1} in prim {2}, localID {3}, timeout was {4} ms" ,
ScriptName , ItemID , PrimName , LocalID , timeout ) ;
2012-03-14 00:29:36 +00:00
workItem . Abort ( ) ;
2012-03-12 21:16:05 +00:00
}
2008-08-27 22:38:36 +00:00
2012-03-15 02:02:31 +00:00
lock ( EventQueue )
2008-08-27 22:38:36 +00:00
{
2012-03-14 00:29:36 +00:00
m_CurrentWorkItem = null ;
2008-08-27 22:38:36 +00:00
}
return true ;
}
public void SetState ( string state )
{
2008-09-09 01:24:58 +00:00
if ( state = = State )
return ;
2008-08-27 22:38:36 +00:00
PostEvent ( new EventParams ( "state_exit" , new Object [ 0 ] ,
new DetectParams [ 0 ] ) ) ;
PostEvent ( new EventParams ( "state" , new Object [ ] { state } ,
new DetectParams [ 0 ] ) ) ;
PostEvent ( new EventParams ( "state_entry" , new Object [ 0 ] ,
new DetectParams [ 0 ] ) ) ;
2008-09-26 02:51:00 +00:00
throw new EventAbortException ( ) ;
2008-08-27 22:38:36 +00:00
}
2012-03-14 00:29:36 +00:00
/// <summary>
/// Post an event to this script instance.
/// </summary>
/// <remarks>
/// The request to run the event is sent
/// </remarks>
/// <param name="data"></param>
2008-08-27 22:38:36 +00:00
public void PostEvent ( EventParams data )
{
2009-02-22 01:26:18 +00:00
// m_log.DebugFormat("[Script] Posted event {2} in state {3} to {0}.{1}",
2012-03-15 02:02:31 +00:00
// PrimName, ScriptName, data.EventName, State);
2008-08-27 22:38:36 +00:00
if ( ! Running )
return ;
2008-12-21 19:04:06 +00:00
// If min event delay is set then ignore any events untill the time has expired
// This currently only allows 1 event of any type in the given time period.
// This may need extending to allow for a time for each individual event type.
if ( m_eventDelayTicks ! = 0 )
{
if ( DateTime . Now . Ticks < m_nextEventTimeTicks )
return ;
m_nextEventTimeTicks = DateTime . Now . Ticks + m_eventDelayTicks ;
}
2012-03-15 02:02:31 +00:00
lock ( EventQueue )
2008-08-27 22:38:36 +00:00
{
2012-03-15 02:02:31 +00:00
if ( EventQueue . Count > = m_MaxScriptQueue )
2008-08-27 22:38:36 +00:00
return ;
if ( data . EventName = = "timer" )
{
if ( m_TimerQueued )
return ;
m_TimerQueued = true ;
}
2008-09-17 22:00:56 +00:00
if ( data . EventName = = "control" )
{
int held = ( ( LSL_Types . LSLInteger ) data . Params [ 1 ] ) . value ;
2008-09-18 16:53:26 +00:00
// int changed = ((LSL_Types.LSLInteger)data.Params[2]).value;
2008-09-17 22:00:56 +00:00
// If the last message was a 0 (nothing held)
// and this one is also nothing held, drop it
/ /
if ( m_LastControlLevel = = held & & held = = 0 )
return ;
// If there is one or more queued, then queue
// only changed ones, else queue unconditionally
/ /
if ( m_ControlEventsInQueue > 0 )
{
if ( m_LastControlLevel = = held )
return ;
}
m_LastControlLevel = held ;
m_ControlEventsInQueue + + ;
}
2008-09-18 18:50:39 +00:00
if ( data . EventName = = "collision" )
{
if ( m_CollisionInQueue )
return ;
if ( data . DetectParams = = null )
return ;
m_CollisionInQueue = true ;
}
2012-03-15 02:02:31 +00:00
EventQueue . Enqueue ( data ) ;
2008-08-27 22:38:36 +00:00
2012-03-14 00:29:36 +00:00
if ( m_CurrentWorkItem = = null )
2008-08-27 22:38:36 +00:00
{
2012-03-15 02:02:31 +00:00
m_CurrentWorkItem = Engine . QueueEventHandler ( this ) ;
2008-08-27 22:38:36 +00:00
}
}
}
2008-09-16 16:37:16 +00:00
/// <summary>
/// Process the next event queued for this script
/// </summary>
2009-09-30 16:00:09 +00:00
/// <returns></returns>
2008-08-27 22:38:36 +00:00
public object EventProcessor ( )
{
2012-03-15 00:06:52 +00:00
// We check here as the thread stopping this instance from running may itself hold the m_Script lock.
if ( ! Running )
return 0 ;
2008-09-21 02:41:22 +00:00
lock ( m_Script )
2008-08-27 22:38:36 +00:00
{
2011-10-19 20:30:37 +00:00
// m_log.DebugFormat("[XEngine]: EventProcessor() invoked for {0}.{1}", PrimName, ScriptName);
if ( Suspended )
return 0 ;
2008-09-18 18:50:39 +00:00
EventParams data = null ;
2012-03-15 02:02:31 +00:00
lock ( EventQueue )
2008-09-17 22:00:56 +00:00
{
2012-03-15 02:02:31 +00:00
data = ( EventParams ) EventQueue . Dequeue ( ) ;
2008-09-18 18:50:39 +00:00
if ( data = = null ) // Shouldn't happen
{
2012-03-15 02:02:31 +00:00
if ( EventQueue . Count > 0 & & Running & & ! ShuttingDown )
2008-09-18 18:50:39 +00:00
{
2012-03-15 02:02:31 +00:00
m_CurrentWorkItem = Engine . QueueEventHandler ( this ) ;
2008-09-18 18:50:39 +00:00
}
else
{
2012-03-14 00:29:36 +00:00
m_CurrentWorkItem = null ;
2008-09-18 18:50:39 +00:00
}
return 0 ;
}
if ( data . EventName = = "timer" )
m_TimerQueued = false ;
if ( data . EventName = = "control" )
{
if ( m_ControlEventsInQueue > 0 )
m_ControlEventsInQueue - - ;
}
if ( data . EventName = = "collision" )
m_CollisionInQueue = false ;
2008-09-17 22:00:56 +00:00
}
2012-12-12 23:13:34 +00:00
if ( DebugLevel > = 2 )
m_log . DebugFormat (
"[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}" ,
data . EventName ,
ScriptName ,
2013-01-14 23:19:47 +00:00
Part . Name ,
Part . LocalId ,
Part . ParentGroup . Name ,
Part . ParentGroup . UUID ,
Part . AbsolutePosition ,
Part . ParentGroup . Scene . Name ) ;
2008-08-27 22:38:36 +00:00
2008-09-18 18:50:39 +00:00
m_DetectParams = data . DetectParams ;
2008-08-27 22:38:36 +00:00
2008-09-18 18:50:39 +00:00
if ( data . EventName = = "state" ) // Hardcoded state change
2008-08-27 22:38:36 +00:00
{
2012-03-15 02:02:31 +00:00
State = data . Params [ 0 ] . ToString ( ) ;
2012-12-12 23:13:34 +00:00
if ( DebugLevel > = 1 )
m_log . DebugFormat (
"[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}" ,
State ,
ScriptName ,
2013-01-14 23:19:47 +00:00
Part . Name ,
Part . LocalId ,
Part . ParentGroup . Name ,
Part . ParentGroup . UUID ,
Part . AbsolutePosition ,
Part . ParentGroup . Scene . Name ) ;
2012-12-12 23:13:34 +00:00
2014-04-30 19:56:49 +00:00
AsyncCommandManager . StateChange ( Engine ,
2012-03-15 02:02:31 +00:00
LocalID , ItemID ) ;
2008-09-18 18:50:39 +00:00
2013-01-14 23:19:47 +00:00
Part . SetScriptEvents ( ItemID , ( int ) m_Script . GetStateEventFlags ( State ) ) ;
2008-08-27 22:38:36 +00:00
}
2008-09-18 18:50:39 +00:00
else
2008-08-27 22:38:36 +00:00
{
2012-03-15 02:02:31 +00:00
if ( Engine . World . PipeEventsForScript ( LocalID ) | |
2008-09-25 17:26:32 +00:00
data . EventName = = "control" ) // Don't freeze avies!
2008-09-18 18:50:39 +00:00
{
2014-12-10 00:25:27 +00:00
// m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
// PrimName, ScriptName, data.EventName, State);
2008-08-27 22:38:36 +00:00
2008-09-25 17:26:32 +00:00
try
{
m_CurrentEvent = data . EventName ;
m_EventStart = DateTime . Now ;
m_InEvent = true ;
2008-09-07 22:01:25 +00:00
2012-03-16 00:34:30 +00:00
int start = Util . EnvironmentTickCount ( ) ;
// Reset the measurement period when we reach the end of the current one.
if ( start - MeasurementPeriodTickStart > MaxMeasurementPeriod )
MeasurementPeriodTickStart = start ;
2008-09-25 17:26:32 +00:00
m_Script . ExecuteEvent ( State , data . EventName , data . Params ) ;
2008-09-07 22:01:25 +00:00
2012-03-16 00:34:30 +00:00
MeasurementPeriodExecutionTime + = Util . EnvironmentTickCount ( ) - start ;
2008-09-25 17:26:32 +00:00
m_InEvent = false ;
m_CurrentEvent = String . Empty ;
2008-09-07 22:01:25 +00:00
2008-09-25 17:26:32 +00:00
if ( m_SaveState )
{
// This will be the very first event we deliver
2009-02-19 05:16:25 +00:00
// (state_entry) in default state
2008-09-25 17:26:32 +00:00
/ /
2014-12-10 00:25:27 +00:00
SaveState ( ) ;
2008-09-18 18:50:39 +00:00
2008-09-25 17:26:32 +00:00
m_SaveState = false ;
}
}
catch ( Exception e )
2008-08-27 22:38:36 +00:00
{
2012-02-09 00:10:45 +00:00
// m_log.DebugFormat(
// "[SCRIPT] Exception in script {0} {1}: {2}{3}",
// ScriptName, ItemID, e.Message, e.StackTrace);
2008-09-25 17:26:32 +00:00
m_InEvent = false ;
m_CurrentEvent = String . Empty ;
2013-01-16 02:07:43 +00:00
if ( ( ! ( e is TargetInvocationException )
| | ( ! ( e . InnerException is SelfDeleteException )
& & ! ( e . InnerException is ScriptDeleteException )
& & ! ( e . InnerException is ScriptCoopStopException ) ) )
& & ! ( e is ThreadAbortException ) )
2008-08-27 22:38:36 +00:00
{
2008-09-25 17:26:32 +00:00
try
{
// DISPLAY ERROR INWORLD
2008-09-27 05:31:43 +00:00
string text = FormatException ( e ) ;
2008-09-25 17:26:32 +00:00
if ( text . Length > 1000 )
text = text . Substring ( 0 , 1000 ) ;
2012-03-15 02:02:31 +00:00
Engine . World . SimChat ( Utils . StringToBytes ( text ) ,
2008-09-25 17:26:32 +00:00
ChatTypeEnum . DebugChannel , 2147483647 ,
2013-01-14 23:19:47 +00:00
Part . AbsolutePosition ,
Part . Name , Part . UUID , false ) ;
2012-12-06 00:22:52 +00:00
2013-10-30 13:10:29 +00:00
m_log . Debug ( string . Format (
2015-01-08 22:59:29 +00:00
"[SCRIPT INSTANCE]: Runtime error in script {0} (event {1}), part {2} {3} at {4} in {5} " ,
2012-12-06 00:22:52 +00:00
ScriptName ,
2015-01-08 22:59:29 +00:00
data . EventName ,
2012-12-06 00:22:52 +00:00
PrimName ,
2013-01-14 23:19:47 +00:00
Part . UUID ,
Part . AbsolutePosition ,
2013-10-30 13:10:29 +00:00
Part . ParentGroup . Scene . Name ) ,
e ) ;
2008-09-25 17:26:32 +00:00
}
2009-05-22 14:57:00 +00:00
catch ( Exception )
2008-09-25 17:26:32 +00:00
{
2009-05-22 14:57:00 +00:00
}
// catch (Exception e2) // LEGIT: User Scripting
// {
2009-05-18 15:32:06 +00:00
// m_log.Error("[SCRIPT]: "+
// "Error displaying error in-world: " +
// e2.ToString());
// m_log.Error("[SCRIPT]: " +
// "Errormessage: Error compiling script:\r\n" +
// e.ToString());
2009-05-22 14:57:00 +00:00
// }
2008-09-18 18:50:39 +00:00
}
2008-09-25 17:26:32 +00:00
else if ( ( e is TargetInvocationException ) & & ( e . InnerException is SelfDeleteException ) )
2008-09-18 18:50:39 +00:00
{
2008-09-25 17:26:32 +00:00
m_InSelfDelete = true ;
2013-01-14 23:19:47 +00:00
Engine . World . DeleteSceneObject ( Part . ParentGroup , false ) ;
2008-09-18 18:50:39 +00:00
}
2009-04-12 12:03:07 +00:00
else if ( ( e is TargetInvocationException ) & & ( e . InnerException is ScriptDeleteException ) )
{
m_InSelfDelete = true ;
2013-01-14 23:19:47 +00:00
Part . Inventory . RemoveInventoryItem ( ItemID ) ;
2009-04-12 12:03:07 +00:00
}
2013-01-16 02:07:43 +00:00
else if ( ( e is TargetInvocationException ) & & ( e . InnerException is ScriptCoopStopException ) )
{
2013-01-23 23:34:15 +00:00
if ( DebugLevel > = 1 )
m_log . DebugFormat (
"[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively." ,
PrimName , ScriptName , data . EventName , State ) ;
2013-01-16 02:07:43 +00:00
}
2008-08-27 22:38:36 +00:00
}
}
}
2012-03-14 00:29:36 +00:00
// If there are more events and we are currently running and not shutting down, then ask the
// script engine to run the next event.
2012-03-15 02:02:31 +00:00
lock ( EventQueue )
2008-08-27 22:38:36 +00:00
{
2012-12-05 22:33:28 +00:00
EventsProcessed + + ;
2012-03-15 02:02:31 +00:00
if ( EventQueue . Count > 0 & & Running & & ! ShuttingDown )
2008-09-18 18:50:39 +00:00
{
2012-03-15 02:02:31 +00:00
m_CurrentWorkItem = Engine . QueueEventHandler ( this ) ;
2008-09-18 18:50:39 +00:00
}
else
{
2012-03-14 00:29:36 +00:00
m_CurrentWorkItem = null ;
2008-09-18 18:50:39 +00:00
}
2008-08-27 22:38:36 +00:00
}
2008-09-18 18:50:39 +00:00
m_DetectParams = null ;
2008-08-27 22:38:36 +00:00
2008-09-18 18:50:39 +00:00
return 0 ;
}
2008-08-27 22:38:36 +00:00
}
public int EventTime ( )
{
if ( ! m_InEvent )
return 0 ;
return ( DateTime . Now - m_EventStart ) . Seconds ;
}
2012-12-17 21:37:02 +00:00
public void ResetScript ( int timeout )
2008-08-27 22:38:36 +00:00
{
2008-09-03 11:58:36 +00:00
if ( m_Script = = null )
2008-09-03 10:53:25 +00:00
return ;
2008-09-03 11:58:36 +00:00
2008-08-27 22:38:36 +00:00
bool running = Running ;
RemoveState ( ) ;
2008-09-17 22:00:56 +00:00
ReleaseControls ( ) ;
2008-08-27 22:38:36 +00:00
2012-12-17 21:37:02 +00:00
Stop ( timeout ) ;
2013-01-14 23:19:47 +00:00
Part . Inventory . GetInventoryItem ( ItemID ) . PermsMask = 0 ;
Part . Inventory . GetInventoryItem ( ItemID ) . PermsGranter = UUID . Zero ;
2012-03-15 02:02:31 +00:00
AsyncCommandManager . RemoveScript ( Engine , LocalID , ItemID ) ;
EventQueue . Clear ( ) ;
2008-08-27 22:38:36 +00:00
m_Script . ResetVars ( ) ;
2012-03-15 02:02:31 +00:00
State = "default" ;
2008-09-08 22:19:06 +00:00
2013-01-14 23:19:47 +00:00
Part . SetScriptEvents ( ItemID ,
2008-09-08 22:19:06 +00:00
( int ) m_Script . GetStateEventFlags ( State ) ) ;
2008-08-27 22:38:36 +00:00
if ( running )
Start ( ) ;
2015-01-16 22:44:54 +00:00
m_SaveState = StatePersistedHere ;
2008-08-27 22:38:36 +00:00
PostEvent ( new EventParams ( "state_entry" ,
new Object [ 0 ] , new DetectParams [ 0 ] ) ) ;
}
public void ApiResetScript ( )
{
// bool running = Running;
RemoveState ( ) ;
2008-09-17 22:00:56 +00:00
ReleaseControls ( ) ;
2008-08-27 22:38:36 +00:00
m_Script . ResetVars ( ) ;
2013-01-14 23:19:47 +00:00
Part . Inventory . GetInventoryItem ( ItemID ) . PermsMask = 0 ;
Part . Inventory . GetInventoryItem ( ItemID ) . PermsGranter = UUID . Zero ;
2012-03-15 02:02:31 +00:00
AsyncCommandManager . RemoveScript ( Engine , LocalID , ItemID ) ;
2008-09-08 22:19:06 +00:00
2012-03-15 02:02:31 +00:00
EventQueue . Clear ( ) ;
2008-09-08 22:19:06 +00:00
m_Script . ResetVars ( ) ;
2012-03-15 02:02:31 +00:00
State = "default" ;
2008-09-08 22:19:06 +00:00
2013-01-14 23:19:47 +00:00
Part . SetScriptEvents ( ItemID ,
2008-09-08 22:19:06 +00:00
( int ) m_Script . GetStateEventFlags ( State ) ) ;
2008-08-27 22:38:36 +00:00
if ( m_CurrentEvent ! = "state_entry" )
{
2015-01-16 22:44:54 +00:00
m_SaveState = StatePersistedHere ;
2008-08-27 22:38:36 +00:00
PostEvent ( new EventParams ( "state_entry" ,
new Object [ 0 ] , new DetectParams [ 0 ] ) ) ;
2008-09-26 02:51:00 +00:00
throw new EventAbortException ( ) ;
2008-08-27 22:38:36 +00:00
}
}
public Dictionary < string , object > GetVars ( )
{
2011-01-07 00:17:43 +00:00
if ( m_Script ! = null )
return m_Script . GetVars ( ) ;
else
return new Dictionary < string , object > ( ) ;
2008-08-27 22:38:36 +00:00
}
public void SetVars ( Dictionary < string , object > vars )
{
2015-01-22 23:12:10 +00:00
// foreach (KeyValuePair<string, object> kvp in vars)
// m_log.DebugFormat("[SCRIPT INSTANCE]: Setting var {0}={1}", kvp.Key, kvp.Value);
2008-08-27 22:38:36 +00:00
m_Script . SetVars ( vars ) ;
}
public DetectParams GetDetectParams ( int idx )
{
2008-09-18 18:50:39 +00:00
if ( m_DetectParams = = null )
return null ;
2008-08-27 22:38:36 +00:00
if ( idx < 0 | | idx > = m_DetectParams . Length )
return null ;
return m_DetectParams [ idx ] ;
}
2008-09-06 07:52:41 +00:00
public UUID GetDetectID ( int idx )
2008-08-27 22:38:36 +00:00
{
2008-09-18 18:50:39 +00:00
if ( m_DetectParams = = null )
return UUID . Zero ;
2008-08-27 22:38:36 +00:00
if ( idx < 0 | | idx > = m_DetectParams . Length )
2008-09-06 07:52:41 +00:00
return UUID . Zero ;
2008-08-27 22:38:36 +00:00
return m_DetectParams [ idx ] . Key ;
}
2014-12-10 00:25:27 +00:00
public void SaveState ( )
2008-08-27 22:38:36 +00:00
{
2008-09-07 22:01:25 +00:00
// If we're currently in an event, just tell it to save upon return
/ /
2008-09-09 01:26:48 +00:00
if ( m_InEvent )
2008-09-07 22:01:25 +00:00
{
m_SaveState = true ;
return ;
}
2015-01-16 22:44:54 +00:00
// m_log.DebugFormat(
// "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}",
// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
2012-03-15 02:02:31 +00:00
PluginData = AsyncCommandManager . GetSerializationData ( Engine , ItemID ) ;
2008-08-27 22:38:36 +00:00
string xml = ScriptSerializer . Serialize ( this ) ;
2009-10-26 14:50:25 +00:00
// Compare hash of the state we just just created with the state last written to disk
// If the state is different, update the disk file.
2009-10-29 12:56:37 +00:00
UUID hash = UUID . Parse ( Utils . MD5String ( xml ) ) ;
2009-11-23 02:26:06 +00:00
if ( hash ! = m_CurrentStateHash )
2008-08-27 22:38:36 +00:00
{
2009-03-26 14:28:00 +00:00
try
{
2014-12-10 00:25:27 +00:00
using ( FileStream fs = File . Create ( Path . Combine ( m_dataPath , ItemID . ToString ( ) + ".state" ) ) )
2014-12-03 18:58:55 +00:00
{
Byte [ ] buf = Util . UTF8NoBomEncoding . GetBytes ( xml ) ;
fs . Write ( buf , 0 , buf . Length ) ;
}
2009-03-26 14:28:00 +00:00
}
2009-05-22 14:57:00 +00:00
catch ( Exception )
2009-03-26 14:28:00 +00:00
{
2009-05-18 15:32:06 +00:00
// m_log.Error("Unable to save xml\n"+e.ToString());
2009-03-26 14:28:00 +00:00
}
2012-03-15 02:02:31 +00:00
//if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")))
2009-03-26 14:28:00 +00:00
//{
// throw new Exception("Completed persistence save, but no file was created");
//}
2009-10-29 12:56:37 +00:00
m_CurrentStateHash = hash ;
2008-08-27 22:38:36 +00:00
}
}
2008-09-13 14:40:42 +00:00
public IScriptApi GetApi ( string name )
{
if ( m_Apis . ContainsKey ( name ) )
2012-04-23 23:03:57 +00:00
{
// m_log.DebugFormat("[SCRIPT INSTANCE]: Found api {0} in {1}@{2}", name, ScriptName, PrimName);
2008-09-13 14:40:42 +00:00
return m_Apis [ name ] ;
2012-04-23 23:03:57 +00:00
}
// m_log.DebugFormat("[SCRIPT INSTANCE]: Did not find api {0} in {1}@{2}", name, ScriptName, PrimName);
2008-09-13 14:40:42 +00:00
return null ;
}
2008-09-16 16:37:16 +00:00
public override string ToString ( )
{
2012-03-15 02:02:31 +00:00
return String . Format ( "{0} {1} on {2}" , ScriptName , ItemID , PrimName ) ;
2008-09-16 16:37:16 +00:00
}
2008-09-27 05:31:43 +00:00
string FormatException ( Exception e )
{
2008-09-29 10:30:01 +00:00
if ( e . InnerException = = null ) // Not a normal runtime error
return e . ToString ( ) ;
2008-09-27 05:31:43 +00:00
string message = "Runtime error:\n" + e . InnerException . StackTrace ;
string [ ] lines = message . Split ( new char [ ] { '\n' } ) ;
foreach ( string line in lines )
{
if ( line . Contains ( "SecondLife.Script" ) )
{
int idx = line . IndexOf ( ':' ) ;
if ( idx ! = - 1 )
{
string val = line . Substring ( idx + 1 ) ;
int lineNum = 0 ;
if ( int . TryParse ( val , out lineNum ) )
{
KeyValuePair < int , int > pos =
Compiler . FindErrorPosition (
lineNum , 0 , LineMap ) ;
int scriptLine = pos . Key ;
int col = pos . Value ;
if ( scriptLine = = 0 )
scriptLine + + ;
if ( col = = 0 )
col + + ;
message = string . Format ( "Runtime error:\n" +
2009-12-22 09:24:01 +00:00
"({0}): {1}" , scriptLine - 1 ,
2008-09-27 05:31:43 +00:00
e . InnerException . Message ) ;
return message ;
}
}
}
}
2009-05-18 15:32:06 +00:00
// m_log.ErrorFormat("Scripting exception:");
// m_log.ErrorFormat(e.ToString());
2008-10-11 16:32:31 +00:00
return e . ToString ( ) ;
2008-09-27 05:31:43 +00:00
}
2008-11-08 02:24:34 +00:00
public string GetAssemblyName ( )
{
2014-12-10 00:25:27 +00:00
return m_assemblyPath ;
2008-11-08 02:24:34 +00:00
}
public string GetXMLState ( )
{
2008-11-09 19:30:40 +00:00
bool run = Running ;
2008-11-08 02:24:34 +00:00
Stop ( 100 ) ;
2008-11-09 19:30:40 +00:00
Running = run ;
2009-02-19 05:16:25 +00:00
// We should not be doing this, but since we are about to
// dispose this, it really doesn't make a difference
// This is meant to work around a Windows only race
/ /
m_InEvent = false ;
2009-02-19 05:31:17 +00:00
// Force an update of the in-memory plugin data
/ /
2012-03-15 02:02:31 +00:00
PluginData = AsyncCommandManager . GetSerializationData ( Engine , ItemID ) ;
2009-02-19 05:31:17 +00:00
2008-11-08 02:24:34 +00:00
return ScriptSerializer . Serialize ( this ) ;
}
2009-04-15 18:51:17 +00:00
public UUID RegionID
{
get { return m_RegionID ; }
}
2010-04-19 05:29:26 +00:00
public void Suspend ( )
{
2011-10-19 19:24:07 +00:00
Suspended = true ;
2010-04-19 05:29:26 +00:00
}
public void Resume ( )
{
2011-10-19 19:24:07 +00:00
Suspended = false ;
2010-04-19 05:29:26 +00:00
}
2008-08-27 22:38:36 +00:00
}
2013-07-12 17:53:27 +00:00
/// <summary>
/// Xengine event wait handle.
/// </summary>
/// <remarks>
/// This class exists becase XEngineScriptBase gets a reference to this wait handle. We need to make sure that
/// when scripts are running in different AppDomains the lease does not expire.
/// FIXME: Like LSL_Api, etc., this effectively leaks memory since the GC will never collect it. To avoid this,
/// proper remoting sponsorship needs to be implemented across the board.
/// </remarks>
public class XEngineEventWaitHandle : EventWaitHandle
{
public XEngineEventWaitHandle ( bool initialState , EventResetMode mode ) : base ( initialState , mode ) { }
public override Object InitializeLifetimeService ( )
{
return null ;
}
}
2013-10-30 13:10:29 +00:00
}