diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 8a0340f7cb..85b19c067e 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -77,6 +77,7 @@ namespace OpenSim.Framework.Servers.HttpServer // protected HttpListener m_httpListener; protected CoolHTTPListener m_httpListener2; protected Dictionary m_rpcHandlers = new Dictionary(); + protected Dictionary jsonRpcHandlers = new Dictionary(); protected Dictionary m_rpcHandlersKeepAlive = new Dictionary(); protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ protected Dictionary m_llsdHandlers = new Dictionary(); @@ -217,6 +218,37 @@ namespace OpenSim.Framework.Servers.HttpServer return new List(m_rpcHandlers.Keys); } + // JsonRPC + public bool AddJsonRPCHandler(string method, JsonRPCMethod handler) + { + lock(jsonRpcHandlers) + { + jsonRpcHandlers.Add(method, handler); + } + return true; + } + + public JsonRPCMethod GetJsonRPCHandler(string method) + { + lock (jsonRpcHandlers) + { + if (jsonRpcHandlers.ContainsKey(method)) + { + return jsonRpcHandlers[method]; + } + else + { + return null; + } + } + } + + public List GetJsonRpcHandlerKeys() + { + lock (jsonRpcHandlers) + return new List(jsonRpcHandlers.Keys); + } + public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) { //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); @@ -556,10 +588,18 @@ namespace OpenSim.Framework.Servers.HttpServer buffer = HandleLLSDRequests(request, response); break; + + case "application/json-rpc": + if (DebugLevel >= 3) + LogIncomingToContentTypeHandler(request); + + buffer = HandleJsonRpcRequests(request, response); + break; case "text/xml": case "application/xml": case "application/json": + default: //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); // Point of note.. the DoWeHaveA methods check for an EXACT path @@ -985,6 +1025,74 @@ namespace OpenSim.Framework.Servers.HttpServer return buffer; } + // JsonRpc (v2.0 only) + private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response) + { + Stream requestStream = request.InputStream; + JsonRpcResponse jsonRpcResponse = new JsonRpcResponse(); + OSDMap jsonRpcRequest = null; + + try + { + jsonRpcRequest = (OSDMap)OSDParser.DeserializeJson(requestStream); + } + catch (LitJson.JsonException e) + { + jsonRpcResponse.Error.Code = ErrorCode.InternalError; + jsonRpcResponse.Error.Message = e.Message; + } + + requestStream.Close(); + + if (jsonRpcRequest != null) + { + if (jsonRpcRequest.ContainsKey("jsonrpc") || jsonRpcRequest["jsonrpc"].AsString() == "2.0") + { + jsonRpcResponse.JsonRpc = "2.0"; + + // If we have no id, then it's a "notification" + if (jsonRpcRequest.ContainsKey("id")) + { + jsonRpcResponse.Id = jsonRpcRequest["id"].AsString(); + } + + string methodname = jsonRpcRequest["method"]; + JsonRPCMethod method; + + if (jsonRpcHandlers.ContainsKey(methodname)) + { + lock(jsonRpcHandlers) + { + jsonRpcHandlers.TryGetValue(methodname, out method); + } + + method(jsonRpcRequest, ref jsonRpcResponse); + } + else // Error no hanlder defined for requested method + { + jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest; + jsonRpcResponse.Error.Message = string.Format ("No handler defined for {0}", methodname); + } + } + else // not json-rpc 2.0 could be v1 + { + jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest; + jsonRpcResponse.Error.Message = "Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification"; + + if (jsonRpcRequest.ContainsKey("id")) + jsonRpcResponse.Id = jsonRpcRequest["id"].AsString(); + } + } + + response.KeepAlive = true; + string responseData = string.Empty; + + responseData = jsonRpcResponse.Serialize(); + + byte[] buffer = Encoding.UTF8.GetBytes(responseData); + return buffer; + } + private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) { //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs index 0bd3aae7d5..13b5dd334f 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs @@ -97,6 +97,8 @@ namespace OpenSim.Framework.Servers.HttpServer bool AddXmlRPCHandler(string method, XmlRpcMethod handler); bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive); + bool AddJsonRPCHandler(string method, JsonRPCMethod handler); + /// /// Gets the XML RPC handler for given method name /// diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs new file mode 100644 index 0000000000..7334049ab4 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs @@ -0,0 +1,34 @@ +/* + * 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.Net; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public delegate void JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response); +} diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs b/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs new file mode 100644 index 0000000000..2c50587794 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs @@ -0,0 +1,150 @@ +/* + * 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.Net; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public sealed class ErrorCode + { + private ErrorCode() {} + + public const int ParseError = -32700; + public const int InvalidRequest = -32600; + public const int MethodNotFound = -32601; + public const int InvalidParams = -32602; + public const int InternalError = -32604; + + } + + public class JsonRpcError + { + internal OSDMap Error = new OSDMap(); + + public int Code + { + get + { + if (Error.ContainsKey("code")) + return Error["code"].AsInteger(); + else + return 0; + } + set + { + Error["code"] = OSD.FromInteger(value); + } + } + + public string Message + { + get + { + if (Error.ContainsKey("message")) + return Error["message"].AsString(); + else + return null; + } + set + { + Error["message"] = OSD.FromString(value); + } + } + + public OSD Data + { + get; set; + } + } + + public class JsonRpcResponse + { + public string JsonRpc + { + get + { + return Reply["jsonrpc"].AsString(); + } + set + { + Reply["jsonrpc"] = OSD.FromString(value); + } + } + + public string Id + { + get + { + return Reply["id"].AsString(); + } + set + { + Reply["id"] = OSD.FromString(value); + } + } + + public OSD Result + { + get; set; + } + + public JsonRpcError Error + { + get; set; + } + + public OSDMap Reply = new OSDMap(); + + public JsonRpcResponse() + { + Error = new JsonRpcError(); + } + + public string Serialize() + { + if (Result != null) + Reply["result"] = Result; + + if (Error.Code != 0) + { + Reply["error"] = (OSD)Error.Error; + } + + string result = string.Empty; + try + { + result = OSDParser.SerializeJsonString(Reply); + } + catch + { + + } + return result; + } + } +} diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs index ae7d515e13..293887ff9b 100644 --- a/OpenSim/Framework/Servers/MainServer.cs +++ b/OpenSim/Framework/Servers/MainServer.cs @@ -230,6 +230,10 @@ namespace OpenSim.Framework.Servers List poll = httpServer.GetPollServiceHandlerKeys(); foreach (String s in httpServer.GetHTTPHandlerKeys()) handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty)); + + handlers.AppendFormat("* JSONRPC:\n"); + foreach (String s in httpServer.GetJsonRpcHandlerKeys()) + handlers.AppendFormat("\t{0}\n", s); // handlers.AppendFormat("* Agent:\n"); // foreach (String s in httpServer.GetAgentHandlerKeys()) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 77acacf299..0ccd69a70b 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -6427,19 +6427,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; - if (handlerAgentRequestSit != null) - if (!(agentRequestSit.AgentData == null - || agentRequestSit.TargetObject == null - || agentRequestSit.TargetObject.TargetID == null - || agentRequestSit.TargetObject.Offset == null)) - { - var sp = m_scene.GetScenePresence(agentRequestSit.AgentData.AgentID); - if (sp == null || sp.ParentID != 0) // ignore packet if agent is already sitting - return true; - handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID, - agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset); - } + if (handlerAgentRequestSit != null) + handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID, + agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset); } return true; } diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 41ca13b8ea..b1887418ee 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -212,11 +212,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer protected override GridRegion GetFinalDestination(GridRegion region) { int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); - m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags); + m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionName, flags); if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) { - m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID); + m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region is hyperlink"); GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); if (real_destination != null) m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI); diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 5c8b097216..92bf85aabd 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1737,6 +1737,21 @@ namespace OpenSim.Region.Framework.Scenes /// /// The part where the script was rezzed if successful. False otherwise. public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase) + { + return RezNewScript( + agentID, + itemBase, + "default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"); + } + + /// + /// Rez a new script from nothing with given script text. + /// + /// + /// Template item. + /// + /// The part where the script was rezzed if successful. False otherwise. + public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase, string scriptText) { // The part ID is the folder ID! SceneObjectPart part = GetSceneObjectPart(itemBase.Folder); @@ -1757,9 +1772,14 @@ namespace OpenSim.Region.Framework.Scenes return null; } - AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType, - Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"), - agentID); + AssetBase asset + = CreateAsset( + itemBase.Name, + itemBase.Description, + (sbyte)itemBase.AssetType, + Encoding.ASCII.GetBytes(scriptText), + agentID); + AssetService.Store(asset); TaskInventoryItem taskItem = new TaskInventoryItem(); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 0219540841..6979c33d11 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1954,6 +1954,10 @@ namespace OpenSim.Region.Framework.Scenes { if (ParentID != 0) { + var targetPart = m_scene.GetSceneObjectPart(targetID); + if (targetPart != null && targetPart.LocalId == ParentID) + return; // already sitting here, ignore + StandUp(); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs index 9ff7084aed..ae54499716 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs @@ -166,7 +166,7 @@ public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParamet // If Debug logging level, enable logging from the unmanaged code m_DebugLogCallbackHandle = null; - if (BSScene.m_log.IsDebugEnabled || PhysicsScene.PhysicsLogging.Enabled) + if (BSScene.m_log.IsDebugEnabled && PhysicsScene.PhysicsLogging.Enabled) { BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader); if (PhysicsScene.PhysicsLogging.Enabled) @@ -212,6 +212,19 @@ public override void Shutdown(BulletWorld world) { BulletWorldUnman worldu = world as BulletWorldUnman; BSAPICPP.Shutdown2(worldu.ptr); + + if (m_paramsHandle.IsAllocated) + { + m_paramsHandle.Free(); + } + if (m_collisionArrayPinnedHandle.IsAllocated) + { + m_collisionArrayPinnedHandle.Free(); + } + if (m_updateArrayPinnedHandle.IsAllocated) + { + m_updateArrayPinnedHandle.Free(); + } } public override bool PushUpdate(BulletBody obj) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index a5fec87eed..87a06c1453 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -215,7 +215,7 @@ public sealed class BSCharacter : BSPhysObject // Add special movement force to allow avatars to walk up stepped surfaces. moveForce += WalkUpStairs(); - DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); + // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce); }); } @@ -855,7 +855,10 @@ public sealed class BSCharacter : BSPhysObject _rotationalVelocity = entprop.RotationalVelocity; // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. - PositionSanityCheck(true); + if (PositionSanityCheck(true)) + { + entprop.Position = _position; + } // remember the current and last set values LastEntityProperties = CurrentEntityProperties; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index bcebaeccfa..6601479d62 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -124,9 +124,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin static readonly float PIOverTwo = ((float)Math.PI) / 2f; // For debugging, flags to turn on and off individual corrections. - private bool enableAngularVerticalAttraction = true; - private bool enableAngularDeflection = true; - private bool enableAngularBanking = true; + private bool enableAngularVerticalAttraction; + private bool enableAngularDeflection; + private bool enableAngularBanking; public BSDynamics(BSScene myScene, BSPrim myPrim) { @@ -141,8 +141,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin public void SetupVehicleDebugging() { enableAngularVerticalAttraction = true; - enableAngularDeflection = true; - enableAngularBanking = true; + enableAngularDeflection = false; + enableAngularBanking = false; if (BSParam.VehicleDebuggingEnabled != ConfigurationParameters.numericFalse) { enableAngularVerticalAttraction = false; @@ -649,6 +649,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin private Quaternion m_knownOrientation; private Vector3 m_knownRotationalVelocity; private Vector3 m_knownRotationalForce; + private Vector3 m_knownRotationalImpulse; private Vector3 m_knownForwardVelocity; // vehicle relative forward speed private const int m_knownChangedPosition = 1 << 0; @@ -658,9 +659,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin private const int m_knownChangedOrientation = 1 << 4; private const int m_knownChangedRotationalVelocity = 1 << 5; private const int m_knownChangedRotationalForce = 1 << 6; - private const int m_knownChangedTerrainHeight = 1 << 7; - private const int m_knownChangedWaterLevel = 1 << 8; - private const int m_knownChangedForwardVelocity = 1 << 9; + private const int m_knownChangedRotationalImpulse = 1 << 7; + private const int m_knownChangedTerrainHeight = 1 << 8; + private const int m_knownChangedWaterLevel = 1 << 9; + private const int m_knownChangedForwardVelocity = 1 <<10; private void ForgetKnownVehicleProperties() { @@ -700,6 +702,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); } + if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) + Prim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); + if ((m_knownChanged & m_knownChangedRotationalForce) != 0) { Prim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); @@ -843,6 +848,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_knownChanged |= m_knownChangedRotationalForce; m_knownHas |= m_knownChangedRotationalForce; } + private void VehicleAddRotationalImpulse(Vector3 pImpulse) + { + if ((m_knownHas & m_knownChangedRotationalImpulse) == 0) + { + m_knownRotationalImpulse = Vector3.Zero; + m_knownHas |= m_knownChangedRotationalImpulse; + } + m_knownRotationalImpulse += pImpulse; + m_knownChanged |= m_knownChangedRotationalImpulse; + } + // Vehicle relative forward velocity private Vector3 VehicleForwardVelocity { @@ -1031,16 +1047,32 @@ namespace OpenSim.Region.Physics.BulletSPlugin else { // Error is positive if below the target and negative if above. - float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; - float verticalCorrectionVelocity = verticalError / m_VhoverTimescale * pTimestep; + Vector3 hpos = VehiclePosition; + float verticalError = m_VhoverTargetHeight - hpos.Z; + float verticalCorrection = verticalError / m_VhoverTimescale; + verticalCorrection *= m_VhoverEfficiency; + + hpos.Z += verticalCorrection; + VehiclePosition = hpos; + + // Since we are hovering, we need to do the opposite of falling -- get rid of world Z + Vector3 vel = VehicleVelocity; + vel.Z = 0f; + VehicleVelocity = vel; + + /* + float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; + Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity); + verticalCorrection *= m_vehicleMass; // TODO: implement m_VhoverEfficiency correctly - VehicleAddForceImpulse(new Vector3(0f, 0f, verticalCorrectionVelocity)); + VehicleAddForceImpulse(verticalCorrection); + */ - VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corrVel={7}", + VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", Prim.LocalID, VehiclePosition, m_VhoverEfficiency, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, - verticalError, verticalCorrectionVelocity); + verticalError, verticalCorrection); } } @@ -1128,8 +1160,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin if (!Prim.IsColliding && VehicleVelocity.Z > 0.1) { // Get rid of any of the velocity vector that is pushing us up. - VehicleVelocity += new Vector3(0, 0, -VehicleVelocity.Z); + float upVelocity = VehicleVelocity.Z; + VehicleVelocity += new Vector3(0, 0, -upVelocity); + /* // If we're pointed up into the air, we should nose down Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; // The rotation around the Y axis is pitch up or down @@ -1143,11 +1177,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}", Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector); } - else - { - VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2}", - Prim.LocalID, VehicleVelocity, pointingDirection); - } + */ + VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", + Prim.LocalID, Prim.IsColliding, upVelocity, VehicleVelocity); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 5a1b5c7c20..8c9a7745f0 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -108,8 +108,8 @@ public sealed class BSLinksetCompound : BSLinkset // Schedule a refresh to happen after all the other taint processing. private void ScheduleRebuild(BSPhysObject requestor) { - DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2}", - requestor.LocalID, Rebuilding, HasAnyChildren); + DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", + requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); // When rebuilding, it is possible to set properties that would normally require a rebuild. // If already rebuilding, don't request another rebuild. // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. @@ -195,8 +195,11 @@ public sealed class BSLinksetCompound : BSLinkset && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) { // TODO: replace this with are calculation of the child prim's orientation and pos. - updated.LinksetInfo = null; - ScheduleRebuild(updated); + // TODO: for the moment, don't rebuild the compound shape. + // This is often just the car turning its wheels. When we can just reorient the one + // member shape of the compound shape, the overhead of rebuilding won't be a problem. + // updated.LinksetInfo = null; + // ScheduleRebuild(updated); } } @@ -308,7 +311,7 @@ public sealed class BSLinksetCompound : BSLinkset else { // Rebuild the compound shape with the child removed - ScheduleRebuild(child); + ScheduleRebuild(LinksetRoot); } } return; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 27ff0476d1..3e80aa4101 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -94,16 +94,16 @@ public static class BSParam public static float PID_D { get; private set; } // derivative public static float PID_P { get; private set; } // proportional - // Various constants that come from that other virtual world that shall not be named + // Various constants that come from that other virtual world that shall not be named. public const float MinGravityZ = -1f; public const float MaxGravityZ = 28f; public const float MinFriction = 0f; public const float MaxFriction = 255f; - public const float MinDensity = 0f; + public const float MinDensity = 0.01f; public const float MaxDensity = 22587f; public const float MinRestitution = 0f; public const float MaxRestitution = 1f; - public const float MaxAddForceMagnitude = 20000f; + public const float MaxAddForceMagnitude = 20f; // =========================================================================== public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); @@ -318,13 +318,13 @@ public static class BSParam (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); }, (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ), new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , - 0f, // set to zero to disable + 0.3f, // set to zero to disable (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); }, (s) => { return CcdMotionThreshold; }, (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); }, (s,o,v) => { s.PE.SetCcdMotionThreshold(o.PhysBody, v); } ), new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , - 0f, + 0.2f, (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); }, (s) => { return CcdSweptSphereRadius; }, (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); }, @@ -465,7 +465,7 @@ public static class BSParam (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; }, (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ), new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", - ConfigurationParameters.numericFalse, + ConfigurationParameters.numericTrue, (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; }, (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ), diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index addab2955a..9fbfcdcabc 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -442,7 +442,8 @@ public sealed class BSShapeCollection : IDisposable return ret; } - // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. + // Create a mesh, hull or native shape. + // Return 'true' if the prim's shape was changed. public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) { bool ret = false; @@ -472,7 +473,7 @@ public sealed class BSShapeCollection : IDisposable if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); - // It doesn't look like Bullet scales spheres so make sure the scales are all equal + // It doesn't look like Bullet scales native spheres so make sure the scales are all equal if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) { @@ -484,9 +485,9 @@ public sealed class BSShapeCollection : IDisposable { ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", - prim.LocalID, forceRebuild, prim.PhysShape); } + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", + prim.LocalID, forceRebuild, ret, prim.PhysShape); } if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) { @@ -498,9 +499,9 @@ public sealed class BSShapeCollection : IDisposable { ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", - prim.LocalID, forceRebuild, prim.PhysShape); } + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", + prim.LocalID, forceRebuild, ret, prim.PhysShape); } } @@ -513,6 +514,7 @@ public sealed class BSShapeCollection : IDisposable return ret; } + // return 'true' if the prim's shape was changed. public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) { @@ -872,8 +874,7 @@ public sealed class BSShapeCollection : IDisposable { prim.LastAssetBuildFailed = true; BSPhysObject xprim = prim; - DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", - LogHeader, prim.LocalID, prim.LastAssetBuildFailed); + DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lastFailed={1}", prim.LocalID, prim.LastAssetBuildFailed); Util.FireAndForget(delegate { RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; @@ -882,19 +883,34 @@ public sealed class BSShapeCollection : IDisposable BSPhysObject yprim = xprim; // probably not necessary, but, just in case. assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) { - if (!yprim.BaseShape.SculptEntry) - return; - if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) - return; - - yprim.BaseShape.SculptData = asset.Data; - // This will cause the prim to see that the filler shape is not the right - // one and try again to build the object. - // No race condition with the normal shape setting since the rebuild is at taint time. - yprim.ForceBodyShapeRebuild(false); + bool assetFound = false; // DEBUG DEBUG + string mismatchIDs = String.Empty; // DEBUG DEBUG + if (yprim.BaseShape.SculptEntry) + { + if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) + { + yprim.BaseShape.SculptData = asset.Data; + // This will cause the prim to see that the filler shape is not the right + // one and try again to build the object. + // No race condition with the normal shape setting since the rebuild is at taint time. + yprim.ForceBodyShapeRebuild(false /* inTaintTime */); + assetFound = true; + } + else + { + mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; + } + } + DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}", + yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); }); } + else + { + PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", + LogHeader, PhysicsScene.Name); + } }); } else @@ -906,9 +922,9 @@ public sealed class BSShapeCollection : IDisposable } } - // While we figure out the real problem, stick in a simple box for the object. - BulletShape fillinShape = - BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. + BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID); return fillinShape; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index 59cbab9412..d4545f7ffc 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -1,7 +1,14 @@ CURRENT PRIORITIES ================================================= +Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 + Msg Kayaker on OSGrid when working +Teravus llMoveToTarget script debug + Mixing of hover, buoyancy/gravity, moveToTarget, into one force +Boats floating at proper level Nebadon vehicles turning funny in arena limitMotorUp calibration (more down?) +llRotLookAt +llLookAt Vehicle angular vertical attraction Vehicle angular deflection Preferred orientation angular correction fix @@ -9,8 +16,6 @@ vehicle angular banking Avatars walking up stairs (HALF DONE) Radius of the capsule affects ability to climb edges. Vehicle movement on terrain smoothness -Surfboard go wonky when turning - Angular motor direction is global coordinates rather than local coordinates? Boats float low in the water (DONE) Avatar movement flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) @@ -27,6 +32,10 @@ Add material densities to the material types CRASHES ================================================= +Crazyness during 20130115 office hours was PositionAdjustUnderground for both char and prim + m1:logs/20130115.0934/physics-BulletSim-20130115083613.log + Creation of Neb's terrain made the terrain "disappear". Everything started to fall + and then get restored to be above terrain. 20121129.1411: editting/moving phys object across region boundries causes crash getPos-> btRigidBody::upcast -> getBodyType -> BOOM 20121128.1600: mesh object not rezzing (no physics mesh). @@ -111,6 +120,8 @@ Physical and phantom will drop through the terrain LINKSETS ====================================================== +Editing a child of a linkset causes the child to go phantom + Move a child prim once when it is physical and can never move it again without it going phantom Offset the center of the linkset to be the geometric center of all the prims Not quite the same as the center-of-gravity Linksets should allow collisions to individual children @@ -133,6 +144,10 @@ Eliminate collisions between objects in a linkset. (LinksetConstraint) MORE ====================================================== +Create tests for different interface components + Have test objects/scripts measure themselves and turn color if correct/bad + Test functions in SL and calibrate correctness there + Create auto rezzer and tracker to run through the tests Use the HACD convex hull routine in Bullet rather than the C# version. Do we need to do convex hulls all the time? Can complex meshes be left meshes? There is some problem with meshes and collisions @@ -167,6 +182,7 @@ Enforce physical parameter min/max: Restitution [0, 1] http://wiki.secondlife.com/wiki/Physics_Material_Settings_test Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html +Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html INTERNAL IMPROVEMENT/CLEANUP ================================================= @@ -287,4 +303,7 @@ Disable activity of passive linkset children. (DONE) Since the linkset is a compound object, the old prims are left lying around and need to be phantomized so they don't collide, ... Remove HeightmapInfo from terrain specification (DONE) - Since C++ code does not need terrain height, this structure et al are not needed. \ No newline at end of file + Since C++ code does not need terrain height, this structure et al are not needed. +Surfboard go wonky when turning (DONE) + Angular motor direction is global coordinates rather than local coordinates? + (Resolution: made angular motor direction correct coordinate system) \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs index 2027ca6491..d2323f56d1 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs @@ -26,9 +26,11 @@ */ using System; +using System.Threading; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; namespace OpenSim.Region.ScriptEngine.Interfaces { @@ -38,11 +40,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces /// Initialize the API /// /// - /// Each API has an identifier, which is used to load the - /// proper runtime assembly at load time. - /// /param> - /// - /// - void Initialize(IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item); + /// Each API has an identifier, which is used to load the proper runtime assembly at load time. + /// /param> + /// /param> + /// /param> + /// /param> + void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle); } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index 2f5b526c43..f68612c15e 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -28,9 +28,11 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Threading; using OpenMetaverse; using log4net; using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Interfaces; @@ -105,6 +107,11 @@ namespace OpenSim.Region.ScriptEngine.Interfaces /// long MeasurementPeriodExecutionTime { get; } + /// + /// Scene part in which this script instance is contained. + /// + SceneObjectPart Part { get; } + IScriptEngine Engine { get; } UUID AppDomain { get; set; } string PrimName { get; } @@ -124,6 +131,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces uint LocalID { get; } UUID AssetID { get; } + + /// + /// Inventory item containing the script used. + /// + TaskInventoryItem ScriptTask { get; } + Queue EventQueue { get; } /// diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index ea4e609978..d47fd6b5ac 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -83,9 +83,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + protected IScriptEngine m_ScriptEngine; protected SceneObjectPart m_host; + /// + /// Used for script sleeps when we are using co-operative script termination. + /// + /// null if co-operative script termination is not active + EventWaitHandle m_coopSleepHandle; + /// /// The item that hosts this script /// @@ -110,24 +117,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp. protected ISoundModule m_SoundModule = null; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) { - m_ScriptEngine = ScriptEngine; + m_ScriptEngine = scriptEngine; m_host = host; m_item = item; + m_coopSleepHandle = coopSleepHandle; - LoadLimits(); // read script limits from config. + LoadConfig(); m_TransferModule = m_ScriptEngine.World.RequestModuleInterface(); m_UrlModule = m_ScriptEngine.World.RequestModuleInterface(); m_SoundModule = m_ScriptEngine.World.RequestModuleInterface(); - AsyncCommands = new AsyncCommandManager(ScriptEngine); + AsyncCommands = new AsyncCommandManager(m_ScriptEngine); } - /* load configuration items that affect script, object and run-time behavior. */ - private void LoadLimits() + /// + /// Load configuration items that affect script, object and run-time behavior. */ + /// + private void LoadConfig() { m_ScriptDelayFactor = m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); @@ -141,12 +152,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_ScriptEngine.Config.GetInt("NotecardLineReadCharsMax", 255); if (m_notecardLineReadCharsMax > 65535) m_notecardLineReadCharsMax = 65535; + // load limits for particular subsystems. IConfig SMTPConfig; if ((SMTPConfig = m_ScriptEngine.ConfigSource.Configs["SMTP"]) != null) { // there's an smtp config, so load in the snooze time. EMAIL_PAUSE_TIME = SMTPConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME); } + // Rezzing an object with a velocity can create recoil. This feature seems to have been // removed from recent versions of SL. The code computes recoil (vel*mass) and scales // it by this factor. May be zero to turn off recoil all together. @@ -171,7 +184,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api delay = (int)((float)delay * m_ScriptDelayFactor); if (delay == 0) return; - System.Threading.Thread.Sleep(delay); + + Sleep(delay); + } + + protected virtual void Sleep(int delay) + { + if (m_coopSleepHandle == null) + System.Threading.Thread.Sleep(delay); + else if (m_coopSleepHandle.WaitOne(delay)) + throw new ScriptCoopStopException(); } public Scene World @@ -2910,7 +2932,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // m_log.Info("llSleep snoozing " + sec + "s."); m_host.AddScriptLPS(1); - Thread.Sleep((int)(sec * 1000)); + + Sleep((int)(sec * 1000)); } public LSL_Float llGetMass() diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index ceb4660f96..a08ccc889e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs @@ -30,6 +30,7 @@ using System.Reflection; using System.Collections; using System.Collections.Generic; using System.Runtime.Remoting.Lifetime; +using System.Threading; using OpenMetaverse; using Nini.Config; using OpenSim; @@ -61,9 +62,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal bool m_LSFunctionsEnabled = false; internal IScriptModuleComms m_comms = null; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) { - m_ScriptEngine = ScriptEngine; + m_ScriptEngine = scriptEngine; m_host = host; if (m_ScriptEngine.Config.GetBoolean("AllowLightShareFunctions", false)) @@ -92,10 +94,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api get { return m_ScriptEngine.World; } } - // - //Dumps an error message on the debug console. - // - + /// + /// Dumps an error message on the debug console. + /// internal void LSShoutError(string message) { if (message.Length > 1023) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index 8f348332b6..981499ea92 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs @@ -30,6 +30,7 @@ using System.Reflection; using System.Collections; using System.Collections.Generic; using System.Runtime.Remoting.Lifetime; +using System.Threading; using OpenMetaverse; using Nini.Config; using OpenSim; @@ -61,9 +62,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal bool m_MODFunctionsEnabled = false; internal IScriptModuleComms m_comms = null; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) { - m_ScriptEngine = ScriptEngine; + m_ScriptEngine = scriptEngine; m_host = host; m_item = item; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 958a448870..25635ff767 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -142,9 +142,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected IUrlModule m_UrlModule = null; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle) { - m_ScriptEngine = ScriptEngine; + m_ScriptEngine = scriptEngine; m_host = host; m_item = item; diff --git a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs index 5a58f734ff..e02d35ed6d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs @@ -81,6 +81,24 @@ namespace OpenSim.Region.ScriptEngine.Shared } } + /// + /// Used to signal when the script is stopping in co-operation with the script engine + /// (instead of through Thread.Abort()). + /// + [Serializable] + public class ScriptCoopStopException : Exception + { + public ScriptCoopStopException() + { + } + + protected ScriptCoopStopException( + SerializationInfo info, + StreamingContext context) + { + } + } + public class DetectParams { public const int AGENT = 1; diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index f172216de4..75aea2b0b1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -157,9 +157,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public UUID AppDomain { get; set; } - /// - /// Scene part in which this script instance is contained. - /// public SceneObjectPart Part { get; private set; } public string PrimName { get; private set; } @@ -203,49 +200,68 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; + private bool m_coopTermination; + + private EventWaitHandle m_coopSleepHandle; + public void ClearQueue() { m_TimerQueued = false; EventQueue.Clear(); } - public ScriptInstance(IScriptEngine engine, SceneObjectPart part, - UUID itemID, UUID assetID, string assembly, - AppDomain dom, string primName, string scriptName, - int startParam, bool postOnRez, StateSource stateSource, - int maxScriptQueue) + public ScriptInstance( + IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item, + int startParam, bool postOnRez, + int maxScriptQueue) { State = "default"; EventQueue = new Queue(32); Engine = engine; Part = part; - ItemID = itemID; - AssetID = assetID; - PrimName = primName; - ScriptName = scriptName; - m_Assembly = assembly; + 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; StartParam = startParam; m_MaxScriptQueue = maxScriptQueue; - m_stateSource = stateSource; m_postOnRez = postOnRez; m_AttachedAvatar = Part.ParentGroup.AttachedAvatar; m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID; - lock (Part.TaskInventory) + if (Engine.Config.GetString("ScriptStopStrategy", "abort") == "co-op") { - if (Part.TaskInventory.ContainsKey(ItemID)) - { - ScriptTask = Part.TaskInventory[ItemID]; - } + m_coopTermination = true; + m_coopSleepHandle = new AutoResetEvent(false); } + } + + /// + /// Load the script from an assembly into an AppDomain. + /// + /// + /// + /// + public void Load(AppDomain dom, string assembly, StateSource stateSource) + { + m_Assembly = assembly; + m_stateSource = stateSource; ApiManager am = new ApiManager(); foreach (string api in am.GetApis()) { m_Apis[api] = am.CreateApi(api); - m_Apis[api].Initialize(engine, part, ScriptTask); + m_Apis[api].Initialize(Engine, Part, ScriptTask, m_coopSleepHandle); } try @@ -279,7 +295,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // // m_log.Debug("[Script] Script instance created"); - part.SetScriptEvents(ItemID, + Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); } catch (Exception e) @@ -526,9 +542,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } // Wait for the current event to complete. - if (!m_InSelfDelete && workItem.Wait(new TimeSpan((long)timeout * 100000))) + if (!m_InSelfDelete) { - return true; + if (!m_coopTermination) + { + // If we're not co-operative terminating then try and wait for the event to complete before stopping + if (workItem.Wait(new TimeSpan((long)timeout * 100000))) + return true; + } + else + { + 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(); + + // 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. + if (workItem.Wait(TimeSpan.MaxValue)) + { + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}", + ScriptName, ItemID, PrimName, ObjectID); + + return true; + } + } } lock (EventQueue) @@ -541,6 +582,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // 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). + // Co-operative termination should never reach this point. if (!m_InSelfDelete) { m_log.DebugFormat( @@ -780,7 +822,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_InEvent = false; m_CurrentEvent = String.Empty; - if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException)) + if ((!(e is TargetInvocationException) + || (!(e.InnerException is SelfDeleteException) + && !(e.InnerException is ScriptDeleteException) + && !(e.InnerException is ScriptCoopStopException))) + && !(e is ThreadAbortException)) { try { @@ -828,6 +874,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_InSelfDelete = true; Part.Inventory.RemoveInventoryItem(ItemID); } + 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); + } } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs new file mode 100644 index 0000000000..8c3e9e0b47 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -0,0 +1,157 @@ +/* + * 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.Collections.Generic; +using System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Scripting.WorldComm; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.ScriptEngine.XEngine; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests +{ + /// + /// Test that co-operative script thread termination is working correctly. + /// + [TestFixture] + public class CoopTerminationTests : OpenSimTestCase + { + 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 OSChatMessage m_osChatMessageReceived; + + [TestFixtureSetUp] + public void Init() + { + //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); +// Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); + m_xEngine = new OpenSim.Region.ScriptEngine.XEngine.XEngine(); + + IniConfigSource configSource = new IniConfigSource(); + + IConfig startupConfig = configSource.AddConfig("Startup"); + startupConfig.Set("DefaultScriptEngine", "XEngine"); + + IConfig xEngineConfig = configSource.AddConfig("XEngine"); + xEngineConfig.Set("Enabled", "true"); + xEngineConfig.Set("StartDelay", "0"); + + // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call + // to AssemblyResolver.OnAssemblyResolve fails. + xEngineConfig.Set("AppDomainLoading", "false"); + + xEngineConfig.Set("ScriptStopStrategy", "co-op"); + + m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); + SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); + m_scene.StartScripts(); + } + + /// + /// Test co-operative termination on derez of an object containing a script with a long-running event. + /// + /// + /// TODO: Actually compiling the script is incidental to this test. Really want a way to compile test scripts + /// within the build itself. + /// + [Test] + public void TestStopOnLongSleep() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); +// UUID objectId = TestHelpers.ParseTail(0x100); +// UUID itemId = TestHelpers.ParseTail(0x3); + string itemName = "TestStopOnObjectDerezLongSleep() Item"; + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStopOnObjectDerezLongSleep", 0x100); + m_scene.AddNewSceneObject(so, true); + + InventoryItemBase itemTemplate = new InventoryItemBase(); +// itemTemplate.ID = itemId; + itemTemplate.Name = itemName; + itemTemplate.Folder = so.UUID; + itemTemplate.InvType = (int)InventoryType.LSL; + + m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; + + SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate, +@"default +{ + state_entry() + { + llSay(0, ""Thin Lizzy""); + llSleep(60); + } +}"); + + TaskInventoryItem rezzedItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); + + // Wait for the script to start the event before we try stopping it. + m_chatEvent.WaitOne(60000); + + 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. + Thread.Sleep(1000); + + // We need a way of carrying on if StopScript() fail, since it won't return if the script isn't actually + // stopped. This kind of multi-threading is far from ideal in a regression test. + new Thread(() => { m_xEngine.StopScript(rezzedItem.ItemID); m_stoppedEvent.Set(); }).Start(); + + if (!m_stoppedEvent.WaitOne(30000)) + Assert.Fail("Script did not co-operatively stop."); + + bool running; + TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); + Assert.That( + SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True); + Assert.That(running, Is.False); + } + + private void OnChatFromWorld(object sender, OSChatMessage oscm) + { +// Console.WriteLine("Got chat [{0}]", oscm.Message); + + m_osChatMessageReceived = oscm; + m_chatEvent.Set(); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs index cb7291adb9..6dd6c170b7 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs @@ -41,6 +41,7 @@ using OpenSim.Region.OptionalModules.World.NPC; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; @@ -93,7 +94,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests TaskInventoryHelpers.AddSceneObject(m_scene, so1.RootPart, inventoryItemName, itemId, userId); LSL_Api api = new LSL_Api(); - api.Initialize(m_engine, so1.RootPart, null); + api.Initialize(m_engine, so1.RootPart, null, null); // Create a second object SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, userId, "so2", 0x100); @@ -126,7 +127,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10); m_scene.AddSceneObject(so1); LSL_Api api = new LSL_Api(); - api.Initialize(m_engine, so1.RootPart, null); + api.Initialize(m_engine, so1.RootPart, null, null); // Create an object embedded inside the first UUID itemId = TestHelpers.ParseTail(0x20); @@ -136,7 +137,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, user2Id, "so2", 0x100); m_scene.AddSceneObject(so2); LSL_Api api2 = new LSL_Api(); - api2.Initialize(m_engine, so2.RootPart, null); + api2.Initialize(m_engine, so2.RootPart, null, null); // *** Firstly, we test where llAllowInventoryDrop() has not been called. *** api.llGiveInventory(so2.UUID.ToString(), inventoryItemName); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs index d9b17d774f..5b57bbe497 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs @@ -41,6 +41,7 @@ using OpenSim.Region.OptionalModules.World.NPC; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; @@ -104,7 +105,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(grp2); LSL_Api apiGrp1 = new LSL_Api(); - apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); + apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item, null); apiGrp1.llCreateLink(grp2.UUID.ToString(), ScriptBaseClass.TRUE); @@ -131,7 +132,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; LSL_Api apiGrp1 = new LSL_Api(); - apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); + apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item, null); apiGrp1.llBreakLink(2); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs index 98017d86e7..60de5cb62d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs @@ -34,6 +34,7 @@ using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.Framework.Scenes; using Nini.Config; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenMetaverse; using OpenSim.Tests.Common.Mock; @@ -67,7 +68,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests engine.AddRegion(scene); m_lslApi = new LSL_Api(); - m_lslApi.Initialize(engine, part, null); + m_lslApi.Initialize(engine, part, null, null); } [Test] diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs index c41d1e7acf..e97ae06a7f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs @@ -33,6 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.Framework.Scenes; using Nini.Config; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenMetaverse; using System; @@ -66,7 +67,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests engine.AddRegion(scene); m_lslApi = new LSL_Api(); - m_lslApi.Initialize(engine, part, null); + m_lslApi.Initialize(engine, part, null, null); } [Test] diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs index 1381d2b045..c88bad5dfc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs @@ -41,6 +41,7 @@ using OpenSim.Region.OptionalModules.World.NPC; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; @@ -93,7 +94,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, null); + osslApi.Initialize(m_engine, part, null, null); string notecardName = "appearanceNc"; @@ -134,7 +135,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, null); + osslApi.Initialize(m_engine, part, null, null); string notecardName = "appearanceNc"; diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs index 5ed1f3d2cf..b2803a12c0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs @@ -41,6 +41,7 @@ using OpenSim.Region.CoreModules.Framework.InventoryAccess; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; @@ -98,9 +99,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); - new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); // SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ua1.PrincipalID); @@ -144,9 +145,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); - new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); // Create an object embedded inside the first TaskInventoryHelpers.AddNotecard( @@ -192,12 +193,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); - new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null); // Create an object embedded inside the first - TaskInventoryHelpers.AddSceneObject(m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); + TaskInventoryHelpers.AddSceneObject( + m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, ua2); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs index d6c82f1258..1f8a6e5b14 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs @@ -42,6 +42,7 @@ using OpenSim.Region.OptionalModules.World.NPC; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; @@ -99,7 +100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, null); + osslApi.Initialize(m_engine, part, null, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); @@ -125,7 +126,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, so.RootPart, null); + osslApi.Initialize(m_engine, so.RootPart, null, null); bool gotExpectedException = false; try @@ -160,7 +161,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, null); + osslApi.Initialize(m_engine, part, null, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); @@ -194,7 +195,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, null); + osslApi.Initialize(m_engine, part, null, null); osslApi.osOwnerSaveAppearance(firstAppearanceNcName); @@ -232,7 +233,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, null); + osslApi.Initialize(m_engine, part, null, null); osslApi.osOwnerSaveAppearance(firstAppearanceNcName); @@ -284,10 +285,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(otherSo); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, null); + osslApi.Initialize(m_engine, part, null, null); OSSL_Api otherOsslApi = new OSSL_Api(); - otherOsslApi.Initialize(m_engine, otherPart, null); + otherOsslApi.Initialize(m_engine, otherPart, null, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); @@ -331,7 +332,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, null); + osslApi.Initialize(m_engine, part, null, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 8c3bb5b06b..a17a0188bb 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -1284,11 +1284,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_DomainScripts[appDomain].Add(itemID); instance = new ScriptInstance(this, part, - itemID, assetID, assembly, - m_AppDomains[appDomain], - part.ParentGroup.RootPart.Name, - item.Name, startParam, postOnRez, - stateSource, m_MaxScriptQueue); + item, + startParam, postOnRez, + m_MaxScriptQueue); + + instance.Load(m_AppDomains[appDomain], assembly, stateSource); // if (DebugLevel >= 1) // m_log.DebugFormat( @@ -1716,9 +1716,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine IScriptInstance instance = GetInstance(itemID); if (instance != null) + { instance.Stop(m_WaitForEventCompletionOnScriptStop); + } else + { +// m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name); m_runFlags.AddOrUpdate(itemID, false, 240); + } } public DetectParams GetDetectParams(UUID itemID, int idx) diff --git a/TESTING.txt b/TESTING.txt index 08a0698d2f..a7346ff34b 100644 --- a/TESTING.txt +++ b/TESTING.txt @@ -1,4 +1,4 @@ -=== The Quick Guide to OpenSim Unit Testing === +===== The Quick Guide to OpenSim Unit Testing === == Running Tests == diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 74bae01ad3..45c3d401c9 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -929,18 +929,10 @@ MaxObjectMass = 10000.01 - ; Dynamic parameters - LinearDamping = 0.0 - AngularDamping = 0.0 - DeactivationTime = 0.2 CollisionMargin = 0.04 ; Linkset constraint parameters LinkImplementation = 1 ; 0=constraint, 1=compound - LinkConstraintUseFrameOffset = False - LinkConstraintEnableTransMotor = True - LinkConstraintTransMotorMaxVel = 5.0 - LinkConstraintTransMotorMaxForce = 0.1 ; Whether to mesh sculpties MeshSculptedPrim = true diff --git a/prebuild.xml b/prebuild.xml index 4c18aa8a97..abf8f364d7 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2417,7 +2417,9 @@ - + + + @@ -3285,6 +3287,7 @@ + @@ -3308,6 +3311,7 @@ +