Merge branch 'master' of melanie@opensimulator.org:/var/git/opensim
commit
9c99ed26eb
|
@ -77,6 +77,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
|||
// protected HttpListener m_httpListener;
|
||||
protected CoolHTTPListener m_httpListener2;
|
||||
protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>();
|
||||
protected Dictionary<string, JsonRPCMethod> jsonRpcHandlers = new Dictionary<string, JsonRPCMethod>();
|
||||
protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>();
|
||||
protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/
|
||||
protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
|
||||
|
@ -217,6 +218,37 @@ namespace OpenSim.Framework.Servers.HttpServer
|
|||
return new List<string>(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<string> GetJsonRpcHandlerKeys()
|
||||
{
|
||||
lock (jsonRpcHandlers)
|
||||
return new List<string>(jsonRpcHandlers.Keys);
|
||||
}
|
||||
|
||||
public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler)
|
||||
{
|
||||
//m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName);
|
||||
|
@ -557,9 +589,17 @@ 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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the XML RPC handler for given method name
|
||||
/// </summary>
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -231,6 +231,10 @@ namespace OpenSim.Framework.Servers
|
|||
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())
|
||||
// handlers.AppendFormat("\t{0}\n", s);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1737,6 +1737,21 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
/// <param name="itemBase"></param>
|
||||
/// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
|
||||
public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase)
|
||||
{
|
||||
return RezNewScript(
|
||||
agentID,
|
||||
itemBase,
|
||||
"default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rez a new script from nothing with given script text.
|
||||
/// </summary>
|
||||
/// <param name="remoteClient"></param>
|
||||
/// <param name="itemBase">Template item.</param>
|
||||
/// <param name="scriptText"></param>
|
||||
/// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
|
||||
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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; } ),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
=================================================
|
||||
|
@ -288,3 +304,6 @@ Disable activity of passive linkset children. (DONE)
|
|||
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.
|
||||
Surfboard go wonky when turning (DONE)
|
||||
Angular motor direction is global coordinates rather than local coordinates?
|
||||
(Resolution: made angular motor direction correct coordinate system)
|
|
@ -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
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Each API has an identifier, which is used to load the
|
||||
/// proper runtime assembly at load time.
|
||||
/// <param name='engine'>/param>
|
||||
/// <param name='part'></param>
|
||||
/// <param name='item'></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 name='scriptEngine'>/param>
|
||||
/// <param name='host'>/param>
|
||||
/// <param name='item'>/param>
|
||||
/// <param name='coopSleepHandle'>/param>
|
||||
void Initialize(
|
||||
IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle);
|
||||
}
|
||||
}
|
|
@ -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
|
|||
/// </summary>
|
||||
long MeasurementPeriodExecutionTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Scene part in which this script instance is contained.
|
||||
/// </summary>
|
||||
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; }
|
||||
|
||||
/// <summary>
|
||||
/// Inventory item containing the script used.
|
||||
/// </summary>
|
||||
TaskInventoryItem ScriptTask { get; }
|
||||
|
||||
Queue EventQueue { get; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Used for script sleeps when we are using co-operative script termination.
|
||||
/// </summary>
|
||||
/// <remarks>null if co-operative script termination is not active</remarks>
|
||||
EventWaitHandle m_coopSleepHandle;
|
||||
|
||||
/// <summary>
|
||||
/// The item that hosts this script
|
||||
/// </summary>
|
||||
|
@ -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<IMessageTransferModule>();
|
||||
m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>();
|
||||
m_SoundModule = m_ScriptEngine.World.RequestModuleInterface<ISoundModule>();
|
||||
|
||||
AsyncCommands = new AsyncCommandManager(ScriptEngine);
|
||||
AsyncCommands = new AsyncCommandManager(m_ScriptEngine);
|
||||
}
|
||||
|
||||
/* load configuration items that affect script, object and run-time behavior. */
|
||||
private void LoadLimits()
|
||||
/// <summary>
|
||||
/// Load configuration items that affect script, object and run-time behavior. */
|
||||
/// </summary>
|
||||
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()
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// Dumps an error message on the debug console.
|
||||
/// </summary>
|
||||
internal void LSShoutError(string message)
|
||||
{
|
||||
if (message.Length > 1023)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -81,6 +81,24 @@ namespace OpenSim.Region.ScriptEngine.Shared
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to signal when the script is stopping in co-operation with the script engine
|
||||
/// (instead of through Thread.Abort()).
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ScriptCoopStopException : Exception
|
||||
{
|
||||
public ScriptCoopStopException()
|
||||
{
|
||||
}
|
||||
|
||||
protected ScriptCoopStopException(
|
||||
SerializationInfo info,
|
||||
StreamingContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class DetectParams
|
||||
{
|
||||
public const int AGENT = 1;
|
||||
|
|
|
@ -157,9 +157,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
|||
|
||||
public UUID AppDomain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scene part in which this script instance is contained.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the script from an assembly into an AppDomain.
|
||||
/// </summary>
|
||||
/// <param name='dom'></param>
|
||||
/// <param name='assembly'></param>
|
||||
/// <param name='stateSource'></param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Test that co-operative script thread termination is working correctly.
|
||||
/// </summary>
|
||||
[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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test co-operative termination on derez of an object containing a script with a long-running event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TODO: Actually compiling the script is incidental to this test. Really want a way to compile test scripts
|
||||
/// within the build itself.
|
||||
/// </remarks>
|
||||
[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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
=== The Quick Guide to OpenSim Unit Testing ===
|
||||
===== The Quick Guide to OpenSim Unit Testing ===
|
||||
|
||||
== Running Tests ==
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2417,7 +2417,9 @@
|
|||
<Reference name="log4net" path="../../../../../bin/"/>
|
||||
|
||||
<Files>
|
||||
<Match pattern="*.cs" recurse="true"/>
|
||||
<Match pattern="*.cs" recurse="true">
|
||||
<Exclude name="Tests" pattern="Tests"/>
|
||||
</Match>
|
||||
</Files>
|
||||
</Project>
|
||||
|
||||
|
@ -3285,6 +3287,7 @@
|
|||
<Reference name="OpenSim.Region.ScriptEngine.Shared"/>
|
||||
<Reference name="OpenSim.Region.ScriptEngine.Shared.Api"/>
|
||||
<Reference name="OpenSim.Region.ScriptEngine.Shared.Api.Runtime"/>
|
||||
<Reference name="OpenSim.Region.ScriptEngine.Shared.Instance"/>
|
||||
<Reference name="OpenSim.Region.ScriptEngine.XEngine"/>
|
||||
<Reference name="OpenSim.Services.Interfaces"/>
|
||||
<Reference name="OpenSim.Tests.Common"/>
|
||||
|
@ -3308,6 +3311,7 @@
|
|||
<!-- SADLY the way this works means you need to keep adding these paths -->
|
||||
<Match path="Shared/Tests" pattern="*.cs" recurse="true"/>
|
||||
<Match path="Shared/CodeTools/Tests" pattern="*.cs" recurse="true"/>
|
||||
<Match path="Shared/Instance/Tests" pattern="*.cs" recurse="true"/>
|
||||
<Match path="XEngine/Tests" pattern="*.cs" recurse="true"/>
|
||||
</Files>
|
||||
</Project>
|
||||
|
|
Loading…
Reference in New Issue