diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs index bc163eb946..2828cab23d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs @@ -140,6 +140,25 @@ public struct EntityProperties public Vector3 Velocity; public Vector3 Acceleration; public Vector3 RotationalVelocity; + + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + buff.Append(""); + return buff.ToString(); + } } // Format of this structure must match the definition in the C++ code diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index dbe44de5f4..fe7891e866 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -690,7 +690,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Bullet does a bunch of smoothing for changing parameters. // Since the vehicle is demanding this setting, we override Bullet's smoothing // by telling Bullet the value was the same last time. - PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity); + // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity); } if ((m_knownChanged & m_knownChangedForce) != 0) @@ -702,7 +702,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) { Prim.ForceRotationalVelocity = m_knownRotationalVelocity; - PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); + // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); } if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) @@ -963,23 +963,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin { // Step the motor from the current value. Get the correction needed this step. Vector3 currentVel = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); - Vector3 linearMotorCorrection = m_linearMotor.Step(pTimestep, currentVel); + Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVel); // Motor is vehicle coordinates. Rotate it to world coordinates - Vector3 linearMotorVelocity = linearMotorCorrection * VehicleOrientation; + Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; // If we're a ground vehicle, don't add any upward Z movement if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0) { - if (linearMotorVelocity.Z > 0f) - linearMotorVelocity.Z = 0f; + if (linearMotorVelocityW.Z > 0f) + linearMotorVelocityW.Z = 0f; } // Add this correction to the velocity to make it faster/slower. - VehicleVelocity += linearMotorVelocity; + VehicleVelocity += linearMotorVelocityW; VDetailLog("{0}, MoveLinear,velocity,vehVel={1},correction={2},force={3}", - Prim.LocalID, VehicleVelocity, linearMotorCorrection, linearMotorVelocity); + Prim.LocalID, VehicleVelocity, linearMotorCorrectionV, linearMotorVelocityW); } public void ComputeLinearTerrainHeightCorrection(float pTimestep) @@ -1123,8 +1123,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin // a downward raycast to find what is below. public void ComputeLinearMotorUp(float pTimestep) { - Vector3 ret = Vector3.Zero; - if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) { // This code tries to decide if the object is not on the ground and then pushing down @@ -1250,8 +1248,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin private void ComputeAngularTurning(float pTimestep) { // The user wants this many radians per second angular change? - Vector3 currentAngular = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation); - Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep, currentAngular); + Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation); + Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV); // ================================================================== // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : @@ -1263,12 +1261,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin // is a linear effect. Where should this check go? if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) { - angularMotorContribution.X = 0f; - angularMotorContribution.Y = 0f; + angularMotorContributionV.X = 0f; + angularMotorContributionV.Y = 0f; } - VehicleRotationalVelocity += angularMotorContribution * VehicleOrientation; - VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); + VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; + VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV); } // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: @@ -1284,7 +1282,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // If vertical attaction timescale is reasonable if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) { - Vector3 vertContribution = Vector3.Zero; + Vector3 vertContributionV = Vector3.Zero; // Take a vector pointing up and convert it from world to vehicle relative coords. Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; @@ -1299,26 +1297,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Y error means needed rotation around X axis and visa versa. // Since the error goes from zero to one, the asin is the corresponding angle. - vertContribution.X = (float)Math.Asin(verticalError.Y); + vertContributionV.X = (float)Math.Asin(verticalError.Y); // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) - vertContribution.Y = -(float)Math.Asin(verticalError.X); + vertContributionV.Y = -(float)Math.Asin(verticalError.X); // If verticalError.Z is negative, the vehicle is upside down. Add additional push. if (verticalError.Z < 0f) { - vertContribution.X += PIOverFour; + vertContributionV.X += PIOverFour; // vertContribution.Y -= PIOverFour; } // 'vertContrbution' is now the necessary angular correction to correct tilt in one second. // Correction happens over a number of seconds. - Vector3 unscaledContrib = vertContribution; // DEBUG DEBUG - vertContribution /= m_verticalAttractionTimescale; + Vector3 unscaledContrib = vertContributionV; // DEBUG DEBUG + vertContributionV /= m_verticalAttractionTimescale; - VehicleRotationalVelocity += vertContribution * VehicleOrientation; + VehicleRotationalVelocity += vertContributionV * VehicleOrientation; VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}", - Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContribution); + Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); } } @@ -1336,7 +1334,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) { - Vector3 deflectContribution = Vector3.Zero; + Vector3 deflectContributionV = Vector3.Zero; // The direction the vehicle is moving Vector3 movingDirection = VehicleVelocity; @@ -1363,13 +1361,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); // Scale the correction by recovery timescale and efficiency - deflectContribution = (-deflectionError) * m_angularDeflectionEfficiency; - deflectContribution /= m_angularDeflectionTimescale; + deflectContributionV = (-deflectionError) * m_angularDeflectionEfficiency; + deflectContributionV /= m_angularDeflectionTimescale; - VehicleRotationalVelocity += deflectContribution * VehicleOrientation; + VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", - Prim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContribution); + Prim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); } @@ -1410,7 +1408,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) { - Vector3 bankingContribution = Vector3.Zero; + Vector3 bankingContributionV = Vector3.Zero; // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented. // As the vehicle rolls to the right or left, the Y value will increase from @@ -1428,15 +1426,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin mixedYawAngle = ClampInRange(-20f, mixedYawAngle, 20f); // Build the force vector to change rotation from what it is to what it should be - bankingContribution.Z = -mixedYawAngle; + bankingContributionV.Z = -mixedYawAngle; // Don't do it all at once. - bankingContribution /= m_bankingTimescale; + bankingContributionV /= m_bankingTimescale; - VehicleRotationalVelocity += bankingContribution * VehicleOrientation; + VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", - Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContribution); + Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 580ea4e689..1e3e5d8f9f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -261,11 +261,6 @@ public abstract class BSLinkset // Called at taint-time!! public abstract bool RemoveBodyDependencies(BSPrim child); - // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', - // this routine will restore the removed constraints. - // Called at taint-time!! - public abstract void RestoreBodyDependencies(BSPrim child); - // ================================================================ protected virtual float ComputeLinksetMass() { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 27d8ad0ef9..2c8dd233d6 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -290,13 +290,6 @@ public sealed class BSLinksetCompound : BSLinkset return ret; } - // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', - // this routine will restore the removed constraints. - // Called at taint-time!! - public override void RestoreBodyDependencies(BSPrim child) - { - } - // When the linkset is built, the child shape is added to the compound shape relative to the // root shape. The linkset then moves around but this does not move the actual child // prim. The child prim's location must be recomputed based on the location of the root shape. @@ -384,7 +377,7 @@ public sealed class BSLinksetCompound : BSLinkset // Constraint linksets are rebuilt every time. // Note that this works for rebuilding just the root after a linkset is taken apart. // Called at taint time!! - private bool disableCOM = true; // disable until we get this debugged + private bool disableCOM = false; // disable until we get this debugged private void RecomputeLinksetCompound() { try @@ -407,12 +400,16 @@ public sealed class BSLinksetCompound : BSLinkset } // DEBUG DEBUG else { - centerOfMass = ComputeLinksetGeometricCenter(); - centerDisplacement = centerOfMass - LinksetRoot.RawPosition; + centerOfMass = ComputeLinksetCenterOfMass(); + // 'centerDisplacement' is the value to *add* to all the shape offsets + centerDisplacement = LinksetRoot.RawPosition - centerOfMass; // Since we're displacing the center of the shape, we need to move the body in the world LinksetRoot.PositionDisplacement = centerDisplacement; + // This causes the root prim position to be set properly based on the new PositionDisplacement + LinksetRoot.ForcePosition = LinksetRoot.RawPosition; + // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0, -centerDisplacement, OMV.Quaternion.Identity, false); DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", LinksetRoot.LocalID, centerOfMass, LinksetRoot.RawPosition, centerDisplacement); @@ -444,7 +441,7 @@ public sealed class BSLinksetCompound : BSLinkset if (cPrim.PhysShape.isNativeShape) { - // A native shape is turning into a hull collision shape because native + // A native shape is turned into a hull collision shape because native // shapes are not shared so we have to hullify it so it will be tracked // and freed at the correct time. This also solves the scaling problem // (native shapes scaled but hull/meshes are assumed to not be). diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 89f186c206..3011465dec 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -110,14 +110,6 @@ public sealed class BSLinksetConstraints : BSLinkset return ret; } - // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', - // this routine will restore the removed constraints. - // Called at taint-time!! - public override void RestoreBodyDependencies(BSPrim child) - { - // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. - } - // ================================================================ // Add a new child to the linkset. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index da7438a4ae..9460daff70 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -645,11 +645,8 @@ public static class BSParam entries.Add(new PhysParameterEntry(pd.name, pd.desc)); } - // make the list in alphabetical order for estetic reasons - entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) - { - return ppe1.name.CompareTo(ppe2.name); - }); + // make the list alphabetical for estetic reasons + entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); }); SettableParameters = entries.ToArray(); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index e6b8507337..f80084a7fd 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -322,6 +322,7 @@ public sealed class BSPrim : BSPhysObject }); } } + public override OMV.Vector3 ForcePosition { get { _position = PhysicsScene.PE.GetPosition(PhysBody) - PositionDisplacement; @@ -336,25 +337,6 @@ public sealed class BSPrim : BSPhysObject } } } - // Override to have position displacement immediately update the physical position. - // A feeble attempt to keep the sim and physical positions in sync - // Must be called at taint time. - public override OMV.Vector3 PositionDisplacement - { - get - { - return base.PositionDisplacement; - } - set - { - base.PositionDisplacement = value; - PhysicsScene.TaintedObject(PhysicsScene.InTaintTime, "BSPrim.setPosition", delegate() - { - if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetTranslation(PhysBody, _position + base.PositionDisplacement, _orientation); - }); - } - } // Check that the current position is sane and, if not, modify the position to make it so. // Check for being below terrain and being out of bounds. @@ -371,11 +353,11 @@ public sealed class BSPrim : BSPhysObject return ret; } - float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); + float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); OMV.Vector3 upForce = OMV.Vector3.Zero; if (RawPosition.Z < terrainHeight) { - DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); + DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); float targetHeight = terrainHeight + (Size.Z / 2f); // If the object is below ground it just has to be moved up because pushing will // not get it through the terrain @@ -1606,11 +1588,6 @@ public sealed class BSPrim : BSPhysObject // Called at taint-time!!! public void CreateGeomAndObject(bool forceRebuild) { - // If this prim is part of a linkset, we must remove and restore the physical - // links if the body is rebuilt. - bool needToRestoreLinkset = false; - bool needToRestoreVehicle = false; - // Create the correct physical representation for this type of object. // Updates PhysBody and PhysShape with the new information. // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. @@ -1619,21 +1596,10 @@ public sealed class BSPrim : BSPhysObject // Called if the current prim body is about to be destroyed. // Remove all the physical dependencies on the old body. // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) - needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); - needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); + Linkset.RemoveBodyDependencies(this); + _vehicle.RemoveBodyDependencies(this); }); - if (needToRestoreLinkset) - { - // If physical body dependencies were removed, restore them - Linkset.RestoreBodyDependencies(this); - } - if (needToRestoreVehicle) - { - // If physical body dependencies were removed, restore them - _vehicle.RestoreBodyDependencies(this); - } - // Make sure the properties are set on the new object UpdatePhysicalParameters(); return; @@ -1653,14 +1619,25 @@ public sealed class BSPrim : BSPhysObject // entprop.RotationalVelocity = OMV.Vector3.Zero; } + // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG + + // Undo any center-of-mass displacement that might have been done. + if (PositionDisplacement != OMV.Vector3.Zero) + { + // Correct for any rotation around the center-of-mass + // TODO!!! + entprop.Position -= PositionDisplacement; + } + // Assign directly to the local variables so the normal set actions do not happen - entprop.Position -= PositionDisplacement; _position = entprop.Position; _orientation = entprop.Rotation; _velocity = entprop.Velocity; _acceleration = entprop.Acceleration; _rotationalVelocity = entprop.RotationalVelocity; + // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG + // The sanity check can change the velocity and/or position. if (IsPhysical && PositionSanityCheck(true)) { @@ -1669,8 +1646,7 @@ public sealed class BSPrim : BSPhysObject } OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG - DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", - LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); + DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); // remember the current and last set values LastEntityProperties = CurrentEntityProperties; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 8075b73b05..34fd2a0531 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -708,8 +708,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // TriggerPreStepEvent // DoOneTimeTaints // Step() - // ProcessAndForwardCollisions - // ProcessAndForwardPropertyUpdates + // ProcessAndSendToSimulatorCollisions + // ProcessAndSendToSimulatorPropertyUpdates // TriggerPostStepEvent // Calls to the PhysicsActors can't directly call into the physics engine diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index 41bab2601d..801f6908ee 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -1,5 +1,7 @@ CURRENT PRIORITIES ================================================= +Deleting a linkset while standing on the root will leave the physical shape of the root behind. + Not sure if it is because standing on it. Done with large prim linksets. Child movement in linkset (don't rebuild linkset) Vehicle angular vertical attraction vehicle angular banking diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs index d2323f56d1..30e99b0d74 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs @@ -46,6 +46,6 @@ namespace OpenSim.Region.ScriptEngine.Interfaces /// /param> /// /param> void Initialize( - IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle); + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle); } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs index 17c270810f..b8fdd01d37 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs @@ -25,16 +25,17 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using log4net; using System; -using OpenSim.Region.ScriptEngine.Shared; +using System.Reflection; +using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; -using OpenMetaverse; -using Nini.Config; using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared; using Amib.Threading; -using OpenSim.Framework; +using log4net; +using Nini.Config; +using OpenMetaverse; namespace OpenSim.Region.ScriptEngine.Interfaces { @@ -76,6 +77,38 @@ namespace OpenSim.Region.ScriptEngine.Interfaces IConfigSource ConfigSource { get; } string ScriptEngineName { get; } string ScriptEnginePath { get; } + + /// + /// Return the name of the class that will be used for all running scripts. + /// + /// + /// Each class goes in its own assembly so we don't need to otherwise distinguish the class name. + /// + string ScriptClassName { get; } + + /// + /// Return the name of the base class that will be used for all running scripts. + /// + string ScriptBaseClassName { get; } + + /// + /// Assemblies that need to be referenced when compiling scripts. + /// + /// + /// These are currently additional to those always referenced by the compiler, BUT THIS MAY CHANGE IN THE + /// FUTURE. + /// This can be null if there are no additional assemblies. + /// + string[] ScriptReferencedAssemblies { get; } + + /// + /// Parameters for the generated script's constructor. + /// + /// + /// Can be null if there are no parameters + /// + ParameterInfo[] ScriptBaseClassParameters { get; } + IScriptApi GetApi(UUID itemID, string name); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs index d03955b559..fce8ff8902 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal TaskInventoryItem m_item; internal bool m_CMFunctionsEnabled = false; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) + public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) { m_ScriptEngine = ScriptEngine; m_host = host; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 9df04dff43..70dea08e52 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -95,7 +95,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Used for script sleeps when we are using co-operative script termination. /// /// null if co-operative script termination is not active - EventWaitHandle m_coopSleepHandle; + WaitHandle m_coopSleepHandle; /// /// The item that hosts this script @@ -150,7 +150,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api }; public void Initialize( - IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) { m_lastSayShoutCheck = DateTime.UtcNow; @@ -227,7 +227,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (m_coopSleepHandle == null) System.Threading.Thread.Sleep(delay); - else if (m_coopSleepHandle.WaitOne(delay)) + else + CheckForCoopTermination(delay); + } + + /// + /// Check for co-operative termination. + /// + /// If called with 0, then just the check is performed with no wait. + protected virtual void CheckForCoopTermination(int delay) + { + if (m_coopSleepHandle.WaitOne(delay)) throw new ScriptCoopStopException(); } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index a08ccc889e..1d6cb6d4dc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal IScriptModuleComms m_comms = null; public void Initialize( - IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) { m_ScriptEngine = scriptEngine; m_host = host; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index 981499ea92..90456721c0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal IScriptModuleComms m_comms = null; public void Initialize( - IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) { m_ScriptEngine = scriptEngine; m_host = host; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 10ec34d0a4..6ff6b00bd1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -144,7 +144,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected IUrlModule m_UrlModule = null; public void Initialize( - IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) { m_ScriptEngine = scriptEngine; m_host = host; diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs index 97dd0f6122..985e598184 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs @@ -49,6 +49,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private List m_warnings = new List(); private IScriptModuleComms m_comms = null; + private bool m_insertCoopTerminationChecks; + private static string m_coopTerminationCheck = "opensim_reserved_CheckForCoopTermination();"; + + /// + /// Keep a record of the previous node when we do the parsing. + /// + /// + /// We do this here because the parser generated by CSTools does not retain a reference to its parent node. + /// The previous node is required so we can correctly insert co-op termination checks when required. + /// +// private SYMBOL m_previousNode; + /// /// Creates an 'empty' CSCodeGenerator instance. /// @@ -58,9 +70,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools ResetCounters(); } - public CSCodeGenerator(IScriptModuleComms comms) + public CSCodeGenerator(IScriptModuleComms comms, bool insertCoopTerminationChecks) { m_comms = comms; + m_insertCoopTerminationChecks = insertCoopTerminationChecks; ResetCounters(); } @@ -155,7 +168,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // here's the payload retstr += GenerateLine(); foreach (SYMBOL s in m_astRoot.kids) - retstr += GenerateNode(s); + retstr += GenerateNode(m_astRoot, s); // close braces! m_braceCount--; @@ -165,7 +178,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // Removes all carriage return characters which may be generated in Windows platform. Is there // cleaner way of doing this? - retstr=retstr.Replace("\r", ""); + retstr = retstr.Replace("\r", ""); return retstr; } @@ -191,9 +204,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// Recursively called to generate each type of node. Will generate this /// node, then all it's children. /// + /// The parent node. /// The current node to generate code for. /// String containing C# code for SYMBOL s. - private string GenerateNode(SYMBOL s) + private string GenerateNode(SYMBOL previousSymbol, SYMBOL s) { string retstr = String.Empty; @@ -207,11 +221,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools else if (s is State) retstr += GenerateState((State) s); else if (s is CompoundStatement) - retstr += GenerateCompoundStatement((CompoundStatement) s); + retstr += GenerateCompoundStatement(previousSymbol, (CompoundStatement) s); else if (s is Declaration) retstr += GenerateDeclaration((Declaration) s); else if (s is Statement) - retstr += GenerateStatement((Statement) s); + retstr += GenerateStatement(previousSymbol, (Statement) s); else if (s is ReturnStatement) retstr += GenerateReturnStatement((ReturnStatement) s); else if (s is JumpLabel) @@ -261,7 +275,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools else { foreach (SYMBOL kid in s.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(s, kid); } return retstr; @@ -295,7 +309,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += GenerateLine(")"); foreach (SYMBOL kid in remainingKids) - retstr += GenerateNode(kid); + retstr += GenerateNode(gf, kid); return retstr; } @@ -312,7 +326,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools foreach (SYMBOL s in gv.kids) { retstr += Indent(); - retstr += GenerateNode(s); + retstr += GenerateNode(gv, s); retstr += GenerateLine(";"); } @@ -365,7 +379,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += GenerateLine(")"); foreach (SYMBOL kid in remainingKids) - retstr += GenerateNode(kid); + retstr += GenerateNode(se, kid); return retstr; } @@ -404,7 +418,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools foreach (SYMBOL s in al.kids) { - retstr += GenerateNode(s); + retstr += GenerateNode(al, s); if (0 < comma--) retstr += Generate(", "); } @@ -417,7 +431,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// /// The CompoundStatement node. /// String containing C# code for CompoundStatement cs. - private string GenerateCompoundStatement(CompoundStatement cs) + private string GenerateCompoundStatement(SYMBOL previousSymbol, CompoundStatement cs) { string retstr = String.Empty; @@ -425,8 +439,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += GenerateIndentedLine("{"); m_braceCount++; + if (m_insertCoopTerminationChecks) + { + // We have to check in event functions as well because the user can manually call these. + if (previousSymbol is GlobalFunctionDefinition + || previousSymbol is WhileStatement + || previousSymbol is DoWhileStatement + || previousSymbol is ForLoop + || previousSymbol is StateEvent) + retstr += GenerateIndentedLine(m_coopTerminationCheck); + } + foreach (SYMBOL kid in cs.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(cs, kid); // closing brace m_braceCount--; @@ -450,13 +475,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// /// The Statement node. /// String containing C# code for Statement s. - private string GenerateStatement(Statement s) + private string GenerateStatement(SYMBOL previousSymbol, Statement s) { string retstr = String.Empty; bool printSemicolon = true; retstr += Indent(); + if (m_insertCoopTerminationChecks) + { + // We have to check in event functions as well because the user can manually call these. + if (previousSymbol is GlobalFunctionDefinition + || previousSymbol is WhileStatement + || previousSymbol is DoWhileStatement + || previousSymbol is ForLoop + || previousSymbol is StateEvent) + retstr += Generate(m_coopTerminationCheck); + } + if (0 < s.kids.Count) { // Jump label prints its own colon, we don't need a semicolon. @@ -466,7 +502,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // (MONO) error. if (!(s.kids.Top is IdentExpression && 1 == s.kids.Count)) foreach (SYMBOL kid in s.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(s, kid); } if (printSemicolon) @@ -487,10 +523,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools List identifiers = new List(); checkForMultipleAssignments(identifiers, a); - retstr += GenerateNode((SYMBOL) a.kids.Pop()); + retstr += GenerateNode(a, (SYMBOL) a.kids.Pop()); retstr += Generate(String.Format(" {0} ", a.AssignmentType), a); foreach (SYMBOL kid in a.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(a, kid); return retstr; } @@ -563,7 +599,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate("return ", rs); foreach (SYMBOL kid in rs.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(rs, kid); return retstr; } @@ -575,7 +611,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// String containing C# code for JumpLabel jl. private string GenerateJumpLabel(JumpLabel jl) { - return Generate(String.Format("{0}:", CheckName(jl.LabelName)), jl) + " NoOp();\n"; + string labelStatement; + + if (m_insertCoopTerminationChecks) + labelStatement = m_coopTerminationCheck + "\n"; + else + labelStatement = "NoOp();\n"; + + return Generate(String.Format("{0}: ", CheckName(jl.LabelName)), jl) + labelStatement; } /// @@ -598,14 +641,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += GenerateIndented("if (", ifs); - retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); retstr += GenerateLine(")"); // CompoundStatement handles indentation itself but we need to do it // otherwise. bool indentHere = ifs.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); if (indentHere) m_braceCount--; if (0 < ifs.kids.Count) // do it again for an else @@ -614,7 +657,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools indentHere = ifs.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); if (indentHere) m_braceCount--; } @@ -641,14 +684,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += GenerateIndented("while (", ws); - retstr += GenerateNode((SYMBOL) ws.kids.Pop()); + retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop()); retstr += GenerateLine(")"); // CompoundStatement handles indentation itself but we need to do it // otherwise. bool indentHere = ws.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) ws.kids.Pop()); + retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop()); if (indentHere) m_braceCount--; return retstr; @@ -669,11 +712,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // otherwise. bool indentHere = dws.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) dws.kids.Pop()); + retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop()); if (indentHere) m_braceCount--; retstr += GenerateIndented("while (", dws); - retstr += GenerateNode((SYMBOL) dws.kids.Pop()); + retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop()); retstr += GenerateLine(");"); return retstr; @@ -702,7 +745,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate("; "); // for (x = 0; x < 10; x++) // ^^^^^^ - retstr += GenerateNode((SYMBOL) fl.kids.Pop()); + retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop()); retstr += Generate("; "); // for (x = 0; x < 10; x++) // ^^^ @@ -713,7 +756,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // otherwise. bool indentHere = fl.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) fl.kids.Pop()); + retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop()); if (indentHere) m_braceCount--; return retstr; @@ -758,7 +801,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools while (s is ParenthesisExpression) s = (SYMBOL)s.kids.Pop(); - retstr += GenerateNode(s); + retstr += GenerateNode(fls, s); if (0 < comma--) retstr += Generate(", "); } @@ -779,20 +822,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { // special case handling for logical and/or, see Mantis 3174 retstr += "((bool)("; - retstr += GenerateNode((SYMBOL)be.kids.Pop()); + retstr += GenerateNode(be, (SYMBOL)be.kids.Pop()); retstr += "))"; retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol.Substring(0,1)), be); retstr += "((bool)("; foreach (SYMBOL kid in be.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(be, kid); retstr += "))"; } else { - retstr += GenerateNode((SYMBOL)be.kids.Pop()); + retstr += GenerateNode(be, (SYMBOL)be.kids.Pop()); retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be); foreach (SYMBOL kid in be.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(be, kid); } return retstr; @@ -808,7 +851,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += Generate(ue.UnarySymbol, ue); - retstr += GenerateNode((SYMBOL) ue.kids.Pop()); + retstr += GenerateNode(ue, (SYMBOL) ue.kids.Pop()); return retstr; } @@ -824,7 +867,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate("("); foreach (SYMBOL kid in pe.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(pe, kid); retstr += Generate(")"); return retstr; @@ -861,7 +904,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // we wrap all typecasted statements in parentheses retstr += Generate(String.Format("({0}) (", te.TypecastType), te); - retstr += GenerateNode((SYMBOL) te.kids.Pop()); + retstr += GenerateNode(te, (SYMBOL) te.kids.Pop()); retstr += Generate(")"); return retstr; @@ -931,7 +974,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools } foreach (SYMBOL kid in fc.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(fc, kid); retstr += Generate(")"); @@ -980,11 +1023,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += Generate(String.Format("new {0}(", vc.Type), vc); - retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); retstr += Generate(")"); return retstr; @@ -1000,13 +1043,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += Generate(String.Format("new {0}(", rc.Type), rc); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(")"); return retstr; @@ -1024,7 +1067,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate(String.Format("new {0}(", lc.Type), lc); foreach (SYMBOL kid in lc.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(lc, kid); retstr += Generate(")"); diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index 03be2abf07..002e8529da 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -31,6 +31,7 @@ using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.IO; +using System.Linq; using System.Text; using Microsoft.CSharp; //using Microsoft.JScript; @@ -72,6 +73,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private bool CompileWithDebugInformation; private Dictionary AllowedCompilers = new Dictionary(StringComparer.CurrentCultureIgnoreCase); private Dictionary LanguageMapping = new Dictionary(StringComparer.CurrentCultureIgnoreCase); + private bool m_insertCoopTerminationCalls; private string FilePrefix; private string ScriptEnginesPath = null; @@ -95,20 +97,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private Dictionary, KeyValuePair>> m_lineMaps = new Dictionary, KeyValuePair>>(); + public bool in_startup = true; + public Compiler(IScriptEngine scriptEngine) { - m_scriptEngine = scriptEngine;; + m_scriptEngine = scriptEngine; ScriptEnginesPath = scriptEngine.ScriptEnginePath; ReadConfig(); } - public bool in_startup = true; public void ReadConfig() { // Get some config WriteScriptSourceToDebugFile = m_scriptEngine.Config.GetBoolean("WriteScriptSourceToDebugFile", false); CompileWithDebugInformation = m_scriptEngine.Config.GetBoolean("CompileWithDebugInformation", true); bool DeleteScriptsOnStartup = m_scriptEngine.Config.GetBoolean("DeleteScriptsOnStartup", true); + m_insertCoopTerminationCalls = m_scriptEngine.Config.GetString("ScriptStopStrategy", "abort") == "co-op"; // Get file prefix from scriptengine name and make it file system safe: FilePrefix = "CommonCompiler"; @@ -386,7 +390,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools if (language == enumCompileType.lsl) { // Its LSL, convert it to C# - LSL_Converter = (ICodeConverter)new CSCodeGenerator(comms); + LSL_Converter = (ICodeConverter)new CSCodeGenerator(comms, m_insertCoopTerminationCalls); compileScript = LSL_Converter.Convert(Script); // copy converter warnings into our warnings. @@ -411,16 +415,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { case enumCompileType.cs: case enumCompileType.lsl: - compileScript = CreateCSCompilerScript(compileScript); + compileScript = CreateCSCompilerScript( + compileScript, + m_scriptEngine.ScriptClassName, + m_scriptEngine.ScriptBaseClassName, + m_scriptEngine.ScriptBaseClassParameters); break; case enumCompileType.vb: - compileScript = CreateVBCompilerScript(compileScript); + compileScript = CreateVBCompilerScript( + compileScript, m_scriptEngine.ScriptClassName, m_scriptEngine.ScriptBaseClassName); break; // case enumCompileType.js: -// compileScript = CreateJSCompilerScript(compileScript); +// compileScript = CreateJSCompilerScript(compileScript, m_scriptEngine.ScriptBaseClassName); // break; case enumCompileType.yp: - compileScript = CreateYPCompilerScript(compileScript); + compileScript = CreateYPCompilerScript( + compileScript, m_scriptEngine.ScriptClassName,m_scriptEngine.ScriptBaseClassName); break; } @@ -451,43 +461,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // return compileScript; // } - private static string CreateCSCompilerScript(string compileScript) + private static string CreateCSCompilerScript( + string compileScript, string className, string baseClassName, ParameterInfo[] constructorParameters) { - compileScript = String.Empty + - "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + - String.Empty + "namespace SecondLife { " + - String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + - @"public Script() { } " + - compileScript + - "} }\r\n"; + compileScript = string.Format( +@"using OpenSim.Region.ScriptEngine.Shared; +using System.Collections.Generic; + +namespace SecondLife +{{ + public class {0} : {1} + {{ + public {0}({2}) : base({3}) {{}} +{4} + }} +}}", + className, + baseClassName, + constructorParameters != null + ? string.Join(", ", Array.ConvertAll(constructorParameters, pi => pi.ToString())) + : "", + constructorParameters != null + ? string.Join(", ", Array.ConvertAll(constructorParameters, pi => pi.Name)) + : "", + compileScript); + return compileScript; } - private static string CreateYPCompilerScript(string compileScript) + private static string CreateYPCompilerScript(string compileScript, string className, string baseClassName) { compileScript = String.Empty + "using OpenSim.Region.ScriptEngine.Shared.YieldProlog; " + "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + String.Empty + "namespace SecondLife { " + - String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + + String.Empty + "public class " + className + " : " + baseClassName + " { \r\n" + //@"public Script() { } " + @"static OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP YP=null; " + - @"public Script() { YP= new OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP(); } " + - + @"public " + className + "() { YP= new OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP(); } " + compileScript + "} }\r\n"; + return compileScript; } - private static string CreateVBCompilerScript(string compileScript) + private static string CreateVBCompilerScript(string compileScript, string className, string baseClassName) { compileScript = String.Empty + "Imports OpenSim.Region.ScriptEngine.Shared: Imports System.Collections.Generic: " + String.Empty + "NameSpace SecondLife:" + - String.Empty + "Public Class Script: Inherits OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass: " + + String.Empty + "Public Class " + className + ": Inherits " + baseClassName + "\r\nPublic Sub New()\r\nEnd Sub: " + compileScript + ":End Class :End Namespace\r\n"; + return compileScript; } @@ -549,6 +576,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenMetaverseTypes.dll")); + if (m_scriptEngine.ScriptReferencedAssemblies != null) + Array.ForEach( + m_scriptEngine.ScriptReferencedAssemblies, + a => parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, a))); + if (lang == enumCompileType.yp) { parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index a869a6af48..891e453ae8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -252,7 +252,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance /// /// /// - public void Load(AppDomain dom, string assembly, StateSource stateSource) + /// false if load failed, true if suceeded + public bool Load(AppDomain dom, string assembly, StateSource stateSource) { m_Assembly = assembly; m_stateSource = stateSource; @@ -267,14 +268,56 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance try { - if (dom != System.AppDomain.CurrentDomain) - m_Script = (IScript)dom.CreateInstanceAndUnwrap( - Path.GetFileNameWithoutExtension(assembly), - "SecondLife.Script"); + object[] constructorParams; + + Assembly scriptAssembly = dom.Load(Path.GetFileNameWithoutExtension(assembly)); + Type scriptType = scriptAssembly.GetType("SecondLife.XEngineScript"); + + if (scriptType != null) + { + constructorParams = new object[] { m_coopSleepHandle }; + } + else if (!m_coopTermination) + { + scriptType = scriptAssembly.GetType("SecondLife.Script"); + constructorParams = null; + } else - m_Script = (IScript)Assembly.Load( - Path.GetFileNameWithoutExtension(assembly)).CreateInstance( - "SecondLife.Script"); + { + m_log.ErrorFormat( + "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. You must remove all existing {6}* script DLL files before using enabling co-op termination" + + ", either by setting DeleteScriptsOnStartup = true in [XEngine] for one run" + + " or by deleting these files manually.", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly); + + return false; + } + +// m_log.DebugFormat( +// "[SCRIPT INSTANCE]: Looking to load {0} from assembly {1} in {2}", +// scriptType.FullName, Path.GetFileNameWithoutExtension(assembly), Engine.World.Name); + + if (dom != System.AppDomain.CurrentDomain) + m_Script + = (IScript)dom.CreateInstanceAndUnwrap( + Path.GetFileNameWithoutExtension(assembly), + scriptType.FullName, + false, + BindingFlags.Default, + null, + constructorParams, + null, + null); + else + m_Script + = (IScript)scriptAssembly.CreateInstance( + scriptType.FullName, + false, + BindingFlags.Default, + null, + constructorParams, + null, + null); //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); @@ -283,8 +326,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance catch (Exception e) { m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Error loading assembly {0}. Exception {1}{2}", - assembly, e.Message, e.StackTrace); + "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error loading assembly {6}. Exception {7}{8}", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, assembly, e.Message, e.StackTrace); + + return false; } try @@ -302,10 +347,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance catch (Exception e) { m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Error loading script instance from assembly {0}. Exception {1}{2}", - assembly, e.Message, e.StackTrace); + "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error initializing script instance. Exception {6}{7}", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, e.Message, e.StackTrace); - return; + return false; } m_SaveState = true; @@ -358,15 +403,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance else { m_log.WarnFormat( - "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). Memory limit exceeded", - savedState, ScriptName, ItemID, PrimName, ObjectID, assembly); + "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState); } } catch (Exception e) { m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). XML is {6}. Exception {7}{8}", - savedState, ScriptName, ItemID, PrimName, ObjectID, assembly, xml, e.Message, e.StackTrace); + "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace); } } // else @@ -377,6 +422,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); // } + + return true; } public void Init() @@ -560,9 +607,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } else { - m_log.DebugFormat( - "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}", - ScriptName, ItemID, PrimName, ObjectID); + if (DebugLevel >= 1) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}", + ScriptName, ItemID, PrimName, ObjectID); // This will terminate the event on next handle check by the script. m_coopSleepHandle.Set(); @@ -571,9 +619,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // checking is implemented. May want to allow a shorter timeout option later. if (workItem.Wait(TimeSpan.MaxValue)) { - m_log.DebugFormat( - "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}", - ScriptName, ItemID, PrimName, ObjectID); + if (DebugLevel >= 1) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}", + ScriptName, ItemID, PrimName, ObjectID); return true; } @@ -894,9 +943,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } else if ((e is TargetInvocationException) && (e.InnerException is ScriptCoopStopException)) { - m_log.DebugFormat( - "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.", - PrimName, ScriptName, data.EventName, State); + if (DebugLevel >= 1) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.", + PrimName, ScriptName, data.EventName, State); } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs index 8c3e9e0b47..52d75a0d31 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -50,14 +50,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests private TestScene m_scene; private OpenSim.Region.ScriptEngine.XEngine.XEngine m_xEngine; - private AutoResetEvent m_chatEvent = new AutoResetEvent(false); - private AutoResetEvent m_stoppedEvent = new AutoResetEvent(false); + private AutoResetEvent m_chatEvent; + private AutoResetEvent m_stoppedEvent; private OSChatMessage m_osChatMessageReceived; - [TestFixtureSetUp] + [SetUp] public void Init() { + m_osChatMessageReceived = null; + m_chatEvent = new AutoResetEvent(false); + m_stoppedEvent = new AutoResetEvent(false); + //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); // Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); m_xEngine = new OpenSim.Region.ScriptEngine.XEngine.XEngine(); @@ -77,7 +81,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests xEngineConfig.Set("ScriptStopStrategy", "co-op"); - m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); + // Make sure loops aren't actually being terminated by a script delay wait. + xEngineConfig.Set("ScriptDelayFactor", 0); + + // This is really just set for debugging the test. + xEngineConfig.Set("WriteScriptSourceToDebugFile", true); + + // Set to false if we need to debug test so the old scripts don't get wiped before each separate test +// xEngineConfig.Set("DeleteScriptsOnStartup", false); + + // This is not currently used at all for co-op termination. Bumping up to demonstrate that co-op termination + // has an effect - without it tests will fail due to a 120 second wait for the event to finish. + xEngineConfig.Set("WaitForEventCompletionOnScriptStop", 120000); + + m_scene = new SceneHelpers().SetupScene("My Test", TestHelpers.ParseTail(0x9999), 1000, 1000, configSource); SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); m_scene.StartScripts(); } @@ -95,12 +112,218 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests TestHelpers.InMethod(); // TestHelpers.EnableLogging(); + string script = +@"default +{ + state_entry() + { + llSay(0, ""Thin Lizzy""); + llSleep(60); + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnLongSingleStatementForLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + for (i = 0; i < 2147483647; i++) + llSay(0, ""Iter "" + (string)i); + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnLongCompoundStatementForLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + for (i = 0; i < 2147483647; i++) + { + llSay(0, ""Iter "" + (string)i); + } + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnLongSingleStatementWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + while (1 == 1) + llSay(0, ""Iter "" + (string)i++); + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnLongCompoundStatementWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + while (1 == 1) + { + llSay(0, ""Iter "" + (string)i++); + } + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnLongDoWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + do + { + llSay(0, ""Iter "" + (string)i++); +} while (1 == 1); + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnInfiniteJumpLoop() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + @p1; + llSay(0, ""Iter "" + (string)i++); + jump p1; + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnInfiniteUserFunctionCallLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@" +integer i = 0; + +ufn1() +{ + llSay(0, ""Iter ufn1() "" + (string)i++); + ufn1(); +} + +default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + ufn1(); + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnInfiniteManualEventCallLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + llSay(0, ""Iter"" + (string)i++); + default_event_state_entry(); + } +}"; + + TestStop(script); + } + + private void TestStop(string script) + { UUID userId = TestHelpers.ParseTail(0x1); // UUID objectId = TestHelpers.ParseTail(0x100); // UUID itemId = TestHelpers.ParseTail(0x3); - string itemName = "TestStopOnObjectDerezLongSleep() Item"; + string itemName = "TestStop() Item"; - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStopOnObjectDerezLongSleep", 0x100); + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStop", 0x100); m_scene.AddNewSceneObject(so, true); InventoryItemBase itemTemplate = new InventoryItemBase(); @@ -111,15 +334,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; - SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate, -@"default -{ - state_entry() - { - llSay(0, ""Thin Lizzy""); - llSleep(60); - } -}"); + SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate, script); TaskInventoryItem rezzedItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); @@ -129,7 +344,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests Console.WriteLine("Script started with message [{0}]", m_osChatMessageReceived.Message); // FIXME: This is a very poor way of trying to avoid a low-probability race condition where the script - // executes llSay() but has not started the sleep before we try to stop it. + // executes llSay() but has not started the next statement before we try to stop it. Thread.Sleep(1000); // We need a way of carrying on if StopScript() fail, since it won't return if the script isn't actually @@ -148,7 +363,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests private void OnChatFromWorld(object sender, OSChatMessage oscm) { -// Console.WriteLine("Got chat [{0}]", oscm.Message); + m_scene.EventManager.OnChatFromWorld -= OnChatFromWorld; + Console.WriteLine("Got chat [{0}]", oscm.Message); m_osChatMessageReceived = oscm; m_chatEvent.Set(); diff --git a/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs b/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs new file mode 100644 index 0000000000..f4211c8286 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs @@ -0,0 +1,61 @@ +/* + * 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 OpenSimulator 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.Runtime.Remoting; +using System.Runtime.Remoting.Lifetime; +using System.Security.Permissions; +using System.Threading; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; + +namespace OpenSim.Region.ScriptEngine.XEngine.ScriptBase +{ + public class XEngineScriptBase : ScriptBaseClass + { + /// + /// Used for script sleeps when we are using co-operative script termination. + /// + /// null if co-operative script termination is not active + WaitHandle m_coopSleepHandle; + + public XEngineScriptBase(WaitHandle coopSleepHandle) : base() + { + m_coopSleepHandle = coopSleepHandle; + } + + public void opensim_reserved_CheckForCoopTermination() + { + if (m_coopSleepHandle != null && m_coopSleepHandle.WaitOne(0)) + throw new ScriptCoopStopException(); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs index 9405075e51..afde685d68 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs @@ -52,7 +52,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine { myScriptEngine = _ScriptEngine; - m_log.Info("[XEngine] Hooking up to server events"); +// m_log.Info("[XEngine] Hooking up to server events"); myScriptEngine.World.EventManager.OnAttach += attach; myScriptEngine.World.EventManager.OnObjectGrab += touch_start; myScriptEngine.World.EventManager.OnObjectGrabbing += touch; @@ -69,7 +69,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine myScriptEngine.World.EventManager.OnScriptLandColliderStart += land_collision_start; myScriptEngine.World.EventManager.OnScriptLandColliding += land_collision; myScriptEngine.World.EventManager.OnScriptLandColliderEnd += land_collision_end; - IMoneyModule money=myScriptEngine.World.RequestModuleInterface(); + IMoneyModule money = myScriptEngine.World.RequestModuleInterface(); if (money != null) { money.OnObjectPaid+=HandleObjectPaid; diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs similarity index 100% rename from OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs rename to OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 816d8baf37..6e04e79f61 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -47,13 +47,15 @@ using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.ScriptEngine.Interfaces; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Region.ScriptEngine.Shared.CodeTools; using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.Api; using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; -using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Region.ScriptEngine.XEngine.ScriptBase; using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; using ScriptCompileQueue = OpenSim.Framework.LocklessQueue; @@ -244,6 +246,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine get { return "XEngine"; } } + public string ScriptClassName { get; private set; } + + public string ScriptBaseClassName { get; private set; } + + public ParameterInfo[] ScriptBaseClassParameters { get; private set; } + + public string[] ScriptReferencedAssemblies { get; private set; } + public Scene World { get { return m_Scene; } @@ -298,21 +308,35 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_ScriptConfig = configSource.Configs["XEngine"]; m_ConfigSource = configSource; + + string rawScriptStopStrategy = m_ScriptConfig.GetString("ScriptStopStrategy", "abort"); + + m_log.InfoFormat("[XEngine]: Script stop strategy is {0}", rawScriptStopStrategy); + + if (rawScriptStopStrategy == "co-op") + { + ScriptClassName = "XEngineScript"; + ScriptBaseClassName = typeof(XEngineScriptBase).FullName; + ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters(); + ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) }; + } + else + { + ScriptClassName = "Script"; + ScriptBaseClassName = typeof(ScriptBaseClass).FullName; + } + +// Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]); } public void AddRegion(Scene scene) { if (m_ScriptConfig == null) return; + m_ScriptFailCount = 0; m_ScriptErrorMessage = String.Empty; - if (m_ScriptConfig == null) - { -// m_log.ErrorFormat("[XEngine] No script configuration found. Scripts disabled"); - return; - } - m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true); if (!m_Enabled) @@ -1180,7 +1204,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine } m_log.DebugFormat( - "[XEngine] Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", + "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); @@ -1201,6 +1225,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine lock (m_AddingAssemblies) { m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap); + if (!m_AddingAssemblies.ContainsKey(assembly)) { m_AddingAssemblies[assembly] = 1; } else { @@ -1250,7 +1275,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine } catch (Exception e) { -// m_log.ErrorFormat("[XEngine]: Exception when rezzing script {0}{1}", e.Message, e.StackTrace); +// m_log.ErrorFormat( +// "[XEngine]: Exception when rezzing script with item ID {0}, {1}{2}", +// itemID, e.Message, e.StackTrace); // try // { @@ -1329,13 +1356,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine 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); + if (!instance.Load(m_AppDomains[appDomain], assembly, stateSource)) + return false; m_AppDomains[appDomain] = sandbox; diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index cc750a9845..26eb8edf39 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -745,13 +745,6 @@ ;; The trade-off may be increased memory usage by the script engine. ; ThreadStackSize = 262144 - ;# {DeleteScriptsOnStartup} {} {Delete previously compiled script DLLs on startup?} (true false) true - ;; Controls whether previously compiled scripts DLLs are deleted on sim restart. If you set this to false - ;; then startup will be considerably faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the - ;; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used - ;; by scripts have changed. - ; DeleteScriptsOnStartup = true - ;; Set this to true (the default) to load each script into a separate ;; AppDomain. ;; @@ -764,6 +757,23 @@ ;; Some Windows users have also reported script loading problems when AppDomainLoading = false ; AppDomainLoading = true + ;; Controls whether scripts are stopped by aborting their threads externally (abort) or by co-operative checks from the compiled script (co-op) + ;; co-op will be more stable but this option is currently experimental. + ;; If moving from co-op to abort, existing script DLLs will need to be recompiled. + ;; This currently can only be done manually, either by setting DeleteScriptsOnStartup = true for one run + ;; or by deleting the script DLL* files in bin/ScriptEngines// + ;; One can move from co-op back to abort without recompilation, but reverting back to co-op again will need script recompile + ;; Current valid values are "abort" and "co-op" + ; ScriptStopStrategy = abort + + + ;# {DeleteScriptsOnStartup} {} {Delete previously compiled script DLLs on startup?} (true false) true + ;; Controls whether previously compiled scripts DLLs are deleted on sim restart. If you set this to false + ;; then startup will be considerably faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the + ;; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used + ;; by scripts have changed. + ; DeleteScriptsOnStartup = true + ;# {DefaultCompileLanguage} {Enabled:true} {Default script language?} {lsl vb cs} lsl ;; Default language for scripts ; DefaultCompileLanguage = "lsl" diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 892290ebdb..fa88146f13 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1311,6 +1311,20 @@ ; script assemblies AppDomainLoading = true + ; Controls whether previously compiled scripts DLLs are deleted on sim restart. If you set this to false + ; then startup will be considerably faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the + ; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used + ; by scripts have changed. + ; DeleteScriptsOnStartup = false + + ; Controls whether scripts are stopped by aborting their threads externally (abort) or by co-operative checks from the compiled script (co-op) + ; co-op will be more stable but this option is currently experimental. + ; If moving from co-op to abort, existing script DLLs will need to be recompiled. + ; This currently can only be done manually, either by setting DeleteScriptsOnStartup = true for one run + ; or by deleting the script DLL* files in bin/ScriptEngines// + ; One can move from co-op back to abort without recompilation, but reverting back to co-op again will need script recompile + ScriptStopStrategy = abort + ; Rate to poll for asynchronous command replies (ms) ; currently unused ;AsyncLLCommandLoopms = 50 @@ -1412,12 +1426,6 @@ ;; Path to script assemblies ; ScriptEnginesPath = "ScriptEngines" - ; Controls whether previously compiled scripts DLLs are deleted on sim restart. If you set this to false - ; then startup will be considerably faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the - ; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used - ; by scripts have changed. - ; DeleteScriptsOnStartup = false - [Concierge] ; Enable concierge module diff --git a/prebuild.xml b/prebuild.xml index c92be99c90..b2c76ea4a3 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2516,6 +2516,40 @@ + + + + ../../../../../../bin/ + + + + + ../../../../../../bin/ + + + + ../../../../../../bin/ + + + + + + + + + + + + + + + + + + + + + @@ -2546,6 +2580,8 @@ + + @@ -2553,6 +2589,7 @@ +