Merge branch 'master' of git://opensimulator.org/git/opensim

user_profiles
Dan Lake 2013-02-14 20:06:22 -08:00
commit e09467b30d
32 changed files with 1000 additions and 259 deletions

View File

@ -535,6 +535,8 @@ namespace OpenSim.Framework.Servers.HttpServer
/// <param name="message"></param> /// <param name="message"></param>
public void Close(string message) public void Close(string message)
{ {
if (_networkContext == null)
return;
if (_networkContext.Stream != null) if (_networkContext.Stream != null)
{ {
if (_networkContext.Stream.CanWrite) if (_networkContext.Stream.CanWrite)

View File

@ -59,6 +59,8 @@ namespace OpenSim.Region.ClientStack.Linden
// private static readonly ILog m_log = // private static readonly ILog m_log =
// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest;
private Scene m_scene; private Scene m_scene;
/// <summary> /// <summary>
@ -94,6 +96,8 @@ namespace OpenSim.Region.ClientStack.Linden
{ {
m_scene = s; m_scene = s;
m_scene.EventManager.OnRegisterCaps += RegisterCaps; m_scene.EventManager.OnRegisterCaps += RegisterCaps;
m_scene.RegisterModuleInterface<ISimulatorFeaturesModule>(this);
} }
public void RemoveRegion(Scene s) public void RemoveRegion(Scene s)
@ -156,7 +160,7 @@ namespace OpenSim.Region.ClientStack.Linden
IRequestHandler reqHandler IRequestHandler reqHandler
= new RestHTTPHandler( = new RestHTTPHandler(
"GET", "/CAPS/" + UUID.Random(), "GET", "/CAPS/" + UUID.Random(),
HandleSimulatorFeaturesRequest, "SimulatorFeatures", agentID.ToString()); x => { return HandleSimulatorFeaturesRequest(x, agentID); }, "SimulatorFeatures", agentID.ToString());
caps.RegisterHandler("SimulatorFeatures", reqHandler); caps.RegisterHandler("SimulatorFeatures", reqHandler);
} }
@ -185,18 +189,33 @@ namespace OpenSim.Region.ClientStack.Linden
return new OSDMap(m_features); return new OSDMap(m_features);
} }
private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod) private OSDMap DeepCopy()
{
// This isn't the cheapest way of doing this but the rate
// of occurrence is low (on sim entry only) and it's a sure
// way to get a true deep copy.
OSD copy = OSDParser.DeserializeLLSDXml(OSDParser.SerializeLLSDXmlString(m_features));
return (OSDMap)copy;
}
private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod, UUID agentID)
{ {
// m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request"); // m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request");
OSDMap copy = DeepCopy();
SimulatorFeaturesRequestDelegate handlerOnSimulatorFeaturesRequest = OnSimulatorFeaturesRequest;
if (handlerOnSimulatorFeaturesRequest != null)
handlerOnSimulatorFeaturesRequest(agentID, ref copy);
//Send back data //Send back data
Hashtable responsedata = new Hashtable(); Hashtable responsedata = new Hashtable();
responsedata["int_response_code"] = 200; responsedata["int_response_code"] = 200;
responsedata["content_type"] = "text/plain"; responsedata["content_type"] = "text/plain";
responsedata["keepalive"] = false; responsedata["keepalive"] = false;
lock (m_features) responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(copy);
responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(m_features);
return responsedata; return responsedata;
} }

View File

@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
public class AssetTransactionModule : INonSharedRegionModule, public class AssetTransactionModule : INonSharedRegionModule,
IAgentAssetTransactions IAgentAssetTransactions
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected Scene m_Scene; protected Scene m_Scene;
private bool m_dumpAssetsToFile = false; private bool m_dumpAssetsToFile = false;

View File

@ -44,7 +44,7 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")] [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")]
public class DAExampleModule : INonSharedRegionModule public class DAExampleModule : INonSharedRegionModule
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly bool ENABLED = false; // enable for testing private static readonly bool ENABLED = false; // enable for testing

View File

@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
try try
{ {
IConfig statConfig = source.Configs["Statistics.Binary"]; IConfig statConfig = source.Configs["Statistics.Binary"];
if (statConfig.Contains("enabled") && statConfig.GetBoolean("enabled")) if (statConfig != null && statConfig.Contains("enabled") && statConfig.GetBoolean("enabled"))
{ {
if (statConfig.Contains("collect_region_stats")) if (statConfig.Contains("collect_region_stats"))
{ {

View File

@ -111,13 +111,15 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC
m_rpcPending = new Dictionary<UUID, RPCRequestInfo>(); m_rpcPending = new Dictionary<UUID, RPCRequestInfo>();
m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>(); m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>();
m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>(); m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>();
if (config.Configs["XMLRPC"] != null)
try
{
m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort);
}
catch (Exception)
{ {
try
{
m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort);
}
catch (Exception)
{
}
} }
} }

View File

@ -31,6 +31,16 @@ using OpenMetaverse;
namespace OpenSim.Region.Framework.Interfaces namespace OpenSim.Region.Framework.Interfaces
{ {
// these could be expanded at some point to provide more type information
// for now value accounts for all base types
public enum JsonStoreNodeType
{
Undefined = 0,
Object = 1,
Array = 2,
Value = 3
}
public delegate void TakeValueCallback(string s); public delegate void TakeValueCallback(string s);
public interface IJsonStoreModule public interface IJsonStoreModule
@ -38,13 +48,18 @@ namespace OpenSim.Region.Framework.Interfaces
bool AttachObjectStore(UUID objectID); bool AttachObjectStore(UUID objectID);
bool CreateStore(string value, ref UUID result); bool CreateStore(string value, ref UUID result);
bool DestroyStore(UUID storeID); bool DestroyStore(UUID storeID);
JsonStoreNodeType GetPathType(UUID storeID, string path);
bool TestStore(UUID storeID); bool TestStore(UUID storeID);
bool TestPath(UUID storeID, string path, bool useJson); bool TestPath(UUID storeID, string path, bool useJson);
bool SetValue(UUID storeID, string path, string value, bool useJson); bool SetValue(UUID storeID, string path, string value, bool useJson);
bool RemoveValue(UUID storeID, string path); bool RemoveValue(UUID storeID, string path);
bool GetValue(UUID storeID, string path, bool useJson, out string value); bool GetValue(UUID storeID, string path, bool useJson, out string value);
void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback);
void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback);
int GetArrayLength(UUID storeID, string path);
} }
} }

View File

@ -26,18 +26,22 @@
*/ */
using System; using System;
using OpenMetaverse;
using OpenMetaverse.StructuredData; using OpenMetaverse.StructuredData;
namespace OpenSim.Region.Framework.Interfaces namespace OpenSim.Region.Framework.Interfaces
{ {
public delegate void SimulatorFeaturesRequestDelegate(UUID agentID, ref OSDMap features);
/// <summary> /// <summary>
/// Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures capability. /// Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures capability.
/// </summary> /// </summary>
public interface ISimulatorFeaturesModule public interface ISimulatorFeaturesModule
{ {
event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest;
void AddFeature(string name, OSD value); void AddFeature(string name, OSD value);
bool RemoveFeature(string name); bool RemoveFeature(string name);
bool TryGetFeature(string name, out OSD value); bool TryGetFeature(string name, out OSD value);
OSDMap GetFeatures(); OSDMap GetFeatures();
} }
} }

View File

@ -790,6 +790,19 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="obj">The object being removed from the scene</param> /// <param name="obj">The object being removed from the scene</param>
public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj); public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj);
/// <summary>
/// Triggered when an object is placed into the physical scene (PhysicsActor created).
/// </summary>
public event Action<SceneObjectPart> OnObjectAddedToPhysicalScene;
/// <summary>
/// Triggered when an object is removed from the physical scene (PhysicsActor destroyed).
/// </summary>
/// <remarks>
/// Note: this is triggered just before the PhysicsActor is removed from the
/// physics engine so the receiver can do any necessary cleanup before its destruction.
/// </remarks>
public event Action<SceneObjectPart> OnObjectRemovedFromPhysicalScene;
/// <summary> /// <summary>
/// Triggered when an object is removed from the scene. /// Triggered when an object is removed from the scene.
/// </summary> /// </summary>
@ -1516,6 +1529,48 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
public void TriggerObjectAddedToPhysicalScene(SceneObjectPart obj)
{
Action<SceneObjectPart> handler = OnObjectAddedToPhysicalScene;
if (handler != null)
{
foreach (Action<SceneObjectPart> d in handler.GetInvocationList())
{
try
{
d(obj);
}
catch (Exception e)
{
m_log.ErrorFormat(
"[EVENT MANAGER]: Delegate for TriggerObjectAddedToPhysicalScene failed - continuing. {0} {1}",
e.Message, e.StackTrace);
}
}
}
}
public void TriggerObjectRemovedFromPhysicalScene(SceneObjectPart obj)
{
Action<SceneObjectPart> handler = OnObjectRemovedFromPhysicalScene;
if (handler != null)
{
foreach (Action<SceneObjectPart> d in handler.GetInvocationList())
{
try
{
d(obj);
}
catch (Exception e)
{
m_log.ErrorFormat(
"[EVENT MANAGER]: Delegate for TriggerObjectRemovedFromPhysicalScene failed - continuing. {0} {1}",
e.Message, e.StackTrace);
}
}
}
}
public void TriggerShutdown() public void TriggerShutdown()
{ {
Action handlerShutdown = OnShutdown; Action handlerShutdown = OnShutdown;

View File

@ -4316,6 +4316,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
PhysActor = pa; PhysActor = pa;
ParentGroup.Scene.EventManager.TriggerObjectAddedToPhysicalScene(this);
} }
/// <summary> /// <summary>
@ -4328,6 +4329,7 @@ namespace OpenSim.Region.Framework.Scenes
/// </remarks> /// </remarks>
public void RemoveFromPhysics() public void RemoveFromPhysics()
{ {
ParentGroup.Scene.EventManager.TriggerObjectRemovedFromPhysicalScene(this);
ParentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); ParentGroup.Scene.PhysicsScene.RemovePrim(PhysActor);
PhysActor = null; PhysActor = null;
} }

View File

@ -68,14 +68,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
protected List<TakeValueCallbackClass> m_TakeStore; protected List<TakeValueCallbackClass> m_TakeStore;
protected List<TakeValueCallbackClass> m_ReadStore; protected List<TakeValueCallbackClass> m_ReadStore;
// add separators for quoted paths // add separators for quoted paths and array references
protected static Regex m_ParsePassOne = new Regex("{[^}]+}"); protected static Regex m_ParsePassOne = new Regex("({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])");
// add separators for array references
protected static Regex m_ParsePassTwo = new Regex("(\\[[0-9]+\\]|\\[\\+\\])");
// add quotes to bare identifiers which are limited to alphabetic characters // add quotes to bare identifiers which are limited to alphabetic characters
protected static Regex m_ParsePassThree = new Regex("\\.([a-zA-Z]+)"); protected static Regex m_ParsePassThree = new Regex("(?<!{[^}]*)\\.([a-zA-Z]+)(?=\\.)");
// remove extra separator characters // remove extra separator characters
protected static Regex m_ParsePassFour = new Regex("\\.+"); protected static Regex m_ParsePassFour = new Regex("\\.+");
@ -84,7 +81,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
protected static Regex m_ValidatePath = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)*$"); protected static Regex m_ValidatePath = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)*$");
// expression used to match path components // expression used to match path components
protected static Regex m_PathComponent = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\]+)"); protected static Regex m_PathComponent = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])");
// extract the internals of an array reference // extract the internals of an array reference
protected static Regex m_SimpleArrayPattern = new Regex("\\[([0-9]+)\\]"); protected static Regex m_SimpleArrayPattern = new Regex("\\[([0-9]+)\\]");
@ -131,15 +128,46 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
m_TakeStore = new List<TakeValueCallbackClass>(); m_TakeStore = new List<TakeValueCallbackClass>();
m_ReadStore = new List<TakeValueCallbackClass>(); m_ReadStore = new List<TakeValueCallbackClass>();
} }
public JsonStore(string value) : this() public JsonStore(string value) : this()
{ {
// This is going to throw an exception if the value is not
// a valid JSON chunk. Calling routines should catch the
// exception and handle it appropriately
if (String.IsNullOrEmpty(value)) if (String.IsNullOrEmpty(value))
ValueStore = new OSDMap(); ValueStore = new OSDMap();
else else
ValueStore = OSDParser.DeserializeJson(value); ValueStore = OSDParser.DeserializeJson(value);
} }
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
public JsonStoreNodeType PathType(string expr)
{
Stack<string> path;
if (! ParsePathExpression(expr,out path))
return JsonStoreNodeType.Undefined;
OSD result = ProcessPathExpression(ValueStore,path);
if (result == null)
return JsonStoreNodeType.Undefined;
if (result is OSDMap)
return JsonStoreNodeType.Object;
if (result is OSDArray)
return JsonStoreNodeType.Array;
if (OSDBaseType(result.Type))
return JsonStoreNodeType.Value;
return JsonStoreNodeType.Undefined;
}
// ----------------------------------------------------------------- // -----------------------------------------------------------------
/// <summary> /// <summary>
/// ///
@ -162,6 +190,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return false; return false;
} }
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
public int ArrayLength(string expr)
{
Stack<string> path;
if (! ParsePathExpression(expr,out path))
return -1;
OSD result = ProcessPathExpression(ValueStore,path);
if (result != null && result.Type == OSDType.Array)
{
OSDArray arr = result as OSDArray;
return arr.Count;
}
return -1;
}
// ----------------------------------------------------------------- // -----------------------------------------------------------------
/// <summary> /// <summary>
/// ///
@ -462,11 +511,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// add front and rear separators // add front and rear separators
expr = "." + expr + "."; expr = "." + expr + ".";
// add separators for quoted exprs // add separators for quoted exprs and array references
expr = m_ParsePassOne.Replace(expr,".$0.",-1,0); expr = m_ParsePassOne.Replace(expr,".$1.",-1,0);
// add separators for array references
expr = m_ParsePassTwo.Replace(expr,".$0.",-1,0);
// add quotes to bare identifier // add quotes to bare identifier
expr = m_ParsePassThree.Replace(expr,".{$1}",-1,0); expr = m_ParsePassThree.Replace(expr,".{$1}",-1,0);
@ -574,14 +620,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// The path pointed to an intermediate hash structure // The path pointed to an intermediate hash structure
if (result.Type == OSDType.Map) if (result.Type == OSDType.Map)
{ {
value = OSDParser.SerializeJsonString(result as OSDMap); value = OSDParser.SerializeJsonString(result as OSDMap,true);
return true; return true;
} }
// The path pointed to an intermediate hash structure // The path pointed to an intermediate hash structure
if (result.Type == OSDType.Array) if (result.Type == OSDType.Array)
{ {
value = OSDParser.SerializeJsonString(result as OSDArray); value = OSDParser.SerializeJsonString(result as OSDArray,true);
return true; return true;
} }

View File

@ -227,7 +227,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
} }
catch (Exception e) catch (Exception e)
{ {
m_log.Error(string.Format("[JsonStore]: Unable to initialize store from {0}", value), e); m_log.ErrorFormat("[JsonStore]: Unable to initialize store from {0}", value);
return false; return false;
} }
@ -265,6 +265,38 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return m_JsonValueStore.ContainsKey(storeID); return m_JsonValueStore.ContainsKey(storeID);
} }
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
public JsonStoreNodeType GetPathType(UUID storeID, string path)
{
if (! m_enabled) return JsonStoreNodeType.Undefined;
JsonStore map = null;
lock (m_JsonValueStore)
{
if (! m_JsonValueStore.TryGetValue(storeID,out map))
{
m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
return JsonStoreNodeType.Undefined;
}
}
try
{
lock (map)
return map.PathType(path);
}
catch (Exception e)
{
m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e);
}
return JsonStoreNodeType.Undefined;
}
// ----------------------------------------------------------------- // -----------------------------------------------------------------
/// <summary> /// <summary>
/// ///
@ -370,6 +402,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return false; return false;
} }
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
public int GetArrayLength(UUID storeID, string path)
{
if (! m_enabled) return -1;
JsonStore map = null;
lock (m_JsonValueStore)
{
if (! m_JsonValueStore.TryGetValue(storeID,out map))
return -1;
}
try
{
lock (map)
{
return map.ArrayLength(path);
}
}
catch (Exception e)
{
m_log.Error("[JsonStore]: unable to retrieve value", e);
}
return -1;
}
// ----------------------------------------------------------------- // -----------------------------------------------------------------
/// <summary> /// <summary>
/// ///

View File

@ -167,7 +167,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
try try
{ {
m_comms.RegisterScriptInvocations(this); m_comms.RegisterScriptInvocations(this);
m_comms.RegisterConstants(this);
// m_comms.RegisterScriptInvocation(this, "JsonCreateStore"); // m_comms.RegisterScriptInvocation(this, "JsonCreateStore");
// m_comms.RegisterScriptInvocation(this, "JsonAttachObjectStore"); // m_comms.RegisterScriptInvocation(this, "JsonAttachObjectStore");
// m_comms.RegisterScriptInvocation(this, "JsonDestroyStore"); // m_comms.RegisterScriptInvocation(this, "JsonDestroyStore");
@ -214,6 +215,22 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
#endregion #endregion
#region ScriptConstantsInterface
[ScriptConstant]
public static readonly int JSON_TYPE_UNDEF = (int)JsonStoreNodeType.Undefined;
[ScriptConstant]
public static readonly int JSON_TYPE_OBJECT = (int)JsonStoreNodeType.Object;
[ScriptConstant]
public static readonly int JSON_TYPE_ARRAY = (int)JsonStoreNodeType.Array;
[ScriptConstant]
public static readonly int JSON_TYPE_VALUE = (int)JsonStoreNodeType.Value;
#endregion
#region ScriptInvocationInteface #region ScriptInvocationInteface
// ----------------------------------------------------------------- // -----------------------------------------------------------------
/// <summary> /// <summary>
@ -318,6 +335,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
/// ///
/// </summary> /// </summary>
// ----------------------------------------------------------------- // -----------------------------------------------------------------
[ScriptInvocation]
public int JsonGetPathType(UUID hostID, UUID scriptID, UUID storeID, string path)
{
return (int)m_store.GetPathType(storeID,path);
}
[ScriptInvocation] [ScriptInvocation]
public int JsonTestPath(UUID hostID, UUID scriptID, UUID storeID, string path) public int JsonTestPath(UUID hostID, UUID scriptID, UUID storeID, string path)
{ {
@ -342,7 +365,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
} }
[ScriptInvocation] [ScriptInvocation]
public int JsonSetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value) public int JsonSetJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value)
{ {
return m_store.SetValue(storeID,path,value,true) ? 1 : 0; return m_store.SetValue(storeID,path,value,true) ? 1 : 0;
} }
@ -358,6 +381,17 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return m_store.RemoveValue(storeID,path) ? 1 : 0; return m_store.RemoveValue(storeID,path) ? 1 : 0;
} }
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
[ScriptInvocation]
public int JsonGetArrayLength(UUID hostID, UUID scriptID, UUID storeID, string path)
{
return m_store.GetArrayLength(storeID,path);
}
// ----------------------------------------------------------------- // -----------------------------------------------------------------
/// <summary> /// <summary>
/// ///
@ -372,7 +406,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
} }
[ScriptInvocation] [ScriptInvocation]
public string JsonGetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) public string JsonGetJson(UUID hostID, UUID scriptID, UUID storeID, string path)
{ {
string value = String.Empty; string value = String.Empty;
m_store.GetValue(storeID,path,true, out value); m_store.GetValue(storeID,path,true, out value);

View File

@ -53,6 +53,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
private Scene m_scene; private Scene m_scene;
private MockScriptEngine m_engine; private MockScriptEngine m_engine;
private ScriptModuleCommsModule m_smcm; private ScriptModuleCommsModule m_smcm;
private JsonStoreScriptModule m_jssm;
[TestFixtureSetUp] [TestFixtureSetUp]
public void FixtureInit() public void FixtureInit()
@ -82,10 +83,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
m_engine = new MockScriptEngine(); m_engine = new MockScriptEngine();
m_smcm = new ScriptModuleCommsModule(); m_smcm = new ScriptModuleCommsModule();
JsonStoreModule jsm = new JsonStoreModule(); JsonStoreModule jsm = new JsonStoreModule();
JsonStoreScriptModule jssm = new JsonStoreScriptModule(); m_jssm = new JsonStoreScriptModule();
m_scene = new SceneHelpers().SetupScene(); m_scene = new SceneHelpers().SetupScene();
SceneHelpers.SetupSceneModules(m_scene, configSource, m_engine, m_smcm, jsm, jssm); SceneHelpers.SetupSceneModules(m_scene, configSource, m_engine, m_smcm, jsm, m_jssm);
try try
{ {
@ -115,8 +116,35 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); // Test blank store
Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); {
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
}
// Test single element store
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
}
// Test with an integer value
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 42.15 }");
Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
string value = (string)InvokeOp("JsonGetValue", storeId, "Hello");
Assert.That(value, Is.EqualTo("42.15"));
}
// Test with an array as the root node
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "[ 'one', 'two', 'three' ]");
Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
string value = (string)InvokeOp("JsonGetValue", storeId, "[1]");
Assert.That(value, Is.EqualTo("two"));
}
} }
[Test] [Test]
@ -181,7 +209,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
} }
[Test] [Test]
public void TestJsonGetValueJson() public void TestJsonGetJson()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
@ -189,26 +217,26 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }"); UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }");
{ {
string value = (string)InvokeOp("JsonGetValueJson", storeId, "Hello.World"); string value = (string)InvokeOp("JsonGetJson", storeId, "Hello.World");
Assert.That(value, Is.EqualTo("'Two'")); Assert.That(value, Is.EqualTo("'Two'"));
} }
// Test get of path section instead of leaf // Test get of path section instead of leaf
{ {
string value = (string)InvokeOp("JsonGetValueJson", storeId, "Hello"); string value = (string)InvokeOp("JsonGetJson", storeId, "Hello");
Assert.That(value, Is.EqualTo("{\"World\":\"Two\"}")); Assert.That(value, Is.EqualTo("{\"World\":\"Two\"}"));
} }
// Test get of non-existing value // Test get of non-existing value
{ {
string fakeValueGet = (string)InvokeOp("JsonGetValueJson", storeId, "foo"); string fakeValueGet = (string)InvokeOp("JsonGetJson", storeId, "foo");
Assert.That(fakeValueGet, Is.EqualTo("")); Assert.That(fakeValueGet, Is.EqualTo(""));
} }
// Test get from non-existing store // Test get from non-existing store
{ {
UUID fakeStoreId = TestHelpers.ParseTail(0x500); UUID fakeStoreId = TestHelpers.ParseTail(0x500);
string fakeStoreValueGet = (string)InvokeOp("JsonGetValueJson", fakeStoreId, "Hello"); string fakeStoreValueGet = (string)InvokeOp("JsonGetJson", fakeStoreId, "Hello");
Assert.That(fakeStoreValueGet, Is.EqualTo("")); Assert.That(fakeStoreValueGet, Is.EqualTo(""));
} }
} }
@ -242,88 +270,236 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); // Test remove of node in object pointing to a string
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
Assert.That(returnValue, Is.EqualTo(1));
int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
Assert.That(result, Is.EqualTo(0));
string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello");
Assert.That(returnValue2, Is.EqualTo(""));
// Test remove of non-existing value
int fakeValueRemove = (int)InvokeOp("JsonRemoveValue", storeId, "Hello");
Assert.That(fakeValueRemove, Is.EqualTo(0));
// Test get from non-existing store
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int fakeStoreValueRemove = (int)InvokeOp("JsonRemoveValue", fakeStoreId, "Hello");
Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
}
[Test]
public void TestJsonTestPath()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }");
{ {
int result = (int)InvokeOp("JsonTestPath", storeId, "Hello.World"); UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
Assert.That(result, Is.EqualTo(1));
} int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
Assert.That(returnValue, Is.EqualTo(1));
// Test for path which does not resolve to a value.
{
int result = (int)InvokeOp("JsonTestPath", storeId, "Hello"); int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
Assert.That(result, Is.EqualTo(0)); Assert.That(result, Is.EqualTo(0));
string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello");
Assert.That(returnValue2, Is.EqualTo(""));
}
// Test remove of node in object pointing to another object
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Wally' } }");
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
Assert.That(returnValue, Is.EqualTo(1));
int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
Assert.That(result, Is.EqualTo(0));
string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello");
Assert.That(returnValue2, Is.EqualTo(""));
}
// Test remove of node in an array
{
UUID storeId
= (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : [ 'value1', 'value2' ] }");
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]");
Assert.That(returnValue, Is.EqualTo(1));
int result = (int)InvokeOp("JsonTestPath", storeId, "Hello[0]");
Assert.That(result, Is.EqualTo(1));
result = (int)InvokeOp("JsonTestPath", storeId, "Hello[1]");
Assert.That(result, Is.EqualTo(0));
string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]");
Assert.That(stringReturnValue, Is.EqualTo("value2"));
stringReturnValue = (string)InvokeOp("JsonGetJson", storeId, "Hello[1]");
Assert.That(stringReturnValue, Is.EqualTo(""));
}
// Test remove of non-existing value
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
int fakeValueRemove = (int)InvokeOp("JsonRemoveValue", storeId, "Cheese");
Assert.That(fakeValueRemove, Is.EqualTo(0));
} }
{ {
int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo"); // Test get from non-existing store
Assert.That(result2, Is.EqualTo(0));
}
// Test with fake store
{
UUID fakeStoreId = TestHelpers.ParseTail(0x500); UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello"); int fakeStoreValueRemove = (int)InvokeOp("JsonRemoveValue", fakeStoreId, "Hello");
Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
} }
} }
// [Test]
// public void TestJsonTestPath()
// {
// TestHelpers.InMethod();
//// TestHelpers.EnableLogging();
//
// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }");
//
// {
// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello.World");
// Assert.That(result, Is.EqualTo(1));
// }
//
// // Test for path which does not resolve to a value.
// {
// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
// Assert.That(result, Is.EqualTo(0));
// }
//
// {
// int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo");
// Assert.That(result2, Is.EqualTo(0));
// }
//
// // Test with fake store
// {
// UUID fakeStoreId = TestHelpers.ParseTail(0x500);
// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello");
// Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
// }
// }
// [Test]
// public void TestJsonTestPathJson()
// {
// TestHelpers.InMethod();
//// TestHelpers.EnableLogging();
//
// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }");
//
// {
// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello.World");
// Assert.That(result, Is.EqualTo(1));
// }
//
// // Test for path which does not resolve to a value.
// {
// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello");
// Assert.That(result, Is.EqualTo(1));
// }
//
// {
// int result2 = (int)InvokeOp("JsonTestPathJson", storeId, "foo");
// Assert.That(result2, Is.EqualTo(0));
// }
//
// // Test with fake store
// {
// UUID fakeStoreId = TestHelpers.ParseTail(0x500);
// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPathJson", fakeStoreId, "Hello");
// Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
// }
// }
[Test] [Test]
public void TestJsonTestPathJson() public void TestGetArrayLength()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }"); UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
{ {
int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello.World"); int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello.World");
Assert.That(result, Is.EqualTo(1)); Assert.That(result, Is.EqualTo(2));
} }
// Test for path which does not resolve to a value. // Test path which is not an array
{ {
int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello"); int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello");
Assert.That(result, Is.EqualTo(1)); Assert.That(result, Is.EqualTo(-1));
} }
// Test fake path
{ {
int result2 = (int)InvokeOp("JsonTestPathJson", storeId, "foo"); int result = (int)InvokeOp("JsonGetArrayLength", storeId, "foo");
Assert.That(result2, Is.EqualTo(0)); Assert.That(result, Is.EqualTo(-1));
} }
// Test with fake store // Test fake store
{ {
UUID fakeStoreId = TestHelpers.ParseTail(0x500); UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int fakeStoreValueRemove = (int)InvokeOp("JsonTestPathJson", fakeStoreId, "Hello"); int result = (int)InvokeOp("JsonGetArrayLength", fakeStoreId, "Hello.World");
Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); Assert.That(result, Is.EqualTo(-1));
}
}
[Test]
public void TestJsonGetPathType()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
{
int result = (int)InvokeOp("JsonGetPathType", storeId, ".");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_ARRAY));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[0]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[1]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
}
// Test for non-existant path
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "foo");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
}
// Test for non-existant store
{
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int result = (int)InvokeOp("JsonGetPathType", fakeStoreId, ".");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
}
}
[Test]
public void TestJsonList2Path()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
// Invoking these methods directly since I just couldn't get comms module invocation to work for some reason
// - some confusion with the methods that take a params object[] invocation.
{
string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo" });
Assert.That(result, Is.EqualTo("{foo}"));
}
{
string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", "bar" });
Assert.That(result, Is.EqualTo("{foo}.{bar}"));
}
{
string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", 1, "bar" });
Assert.That(result, Is.EqualTo("{foo}.[1].{bar}"));
} }
} }
@ -334,7 +510,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
{ {
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times"); int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times");
Assert.That(result, Is.EqualTo(1)); Assert.That(result, Is.EqualTo(1));
@ -343,9 +519,155 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
Assert.That(value, Is.EqualTo("Times")); Assert.That(value, Is.EqualTo("Times"));
} }
// Test setting a key containing periods with delineation
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun.Circus}", "Times");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun.Circus}");
Assert.That(value, Is.EqualTo("Times"));
}
// *** Test [] ***
// Test setting a key containing unbalanced ] without delineation. Expecting failure
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun]Circus", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun]Circus");
Assert.That(value, Is.EqualTo(""));
}
// Test setting a key containing unbalanced [ without delineation. Expecting failure
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[Circus", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[Circus");
Assert.That(value, Is.EqualTo(""));
}
// Test setting a key containing unbalanced [] without delineation. Expecting failure
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[]Circus", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[]Circus");
Assert.That(value, Is.EqualTo(""));
}
// Test setting a key containing unbalanced ] with delineation
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun]Circus}", "Times");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun]Circus}");
Assert.That(value, Is.EqualTo("Times"));
}
// Test setting a key containing unbalanced [ with delineation
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[Circus}", "Times");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[Circus}");
Assert.That(value, Is.EqualTo("Times"));
}
// Test setting a key containing empty balanced [] with delineation
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[]Circus}", "Times");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[]Circus}");
Assert.That(value, Is.EqualTo("Times"));
}
// // Commented out as this currently unexpectedly fails.
// // Test setting a key containing brackets around an integer with delineation
// {
// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
//
// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[0]Circus}", "Times");
// Assert.That(result, Is.EqualTo(1));
//
// string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[0]Circus}");
// Assert.That(value, Is.EqualTo("Times"));
// }
// *** Test {} ***
// Test setting a key containing unbalanced } without delineation. Expecting failure (?)
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun}Circus", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus");
Assert.That(value, Is.EqualTo(""));
}
// Test setting a key containing unbalanced { without delineation. Expecting failure (?)
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun{Circus", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus");
Assert.That(value, Is.EqualTo(""));
}
// // Commented out as this currently unexpectedly fails.
// // Test setting a key containing unbalanced }
// {
// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
//
// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun}Circus}", "Times");
// Assert.That(result, Is.EqualTo(0));
// }
// Test setting a key containing unbalanced { with delineation
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Circus}", "Times");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Circus}");
Assert.That(value, Is.EqualTo("Times"));
}
// Test setting a key containing balanced {} with delineation. This should fail.
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Filled}Circus}", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Filled}Circus}");
Assert.That(value, Is.EqualTo(""));
}
// Test setting to location that does not exist. This should fail. // Test setting to location that does not exist. This should fail.
{ {
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun.Circus", "Times"); int result = (int)InvokeOp("JsonSetValue", storeId, "Fun.Circus", "Times");
Assert.That(result, Is.EqualTo(0)); Assert.That(result, Is.EqualTo(0));
@ -363,27 +685,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
} }
[Test] [Test]
public void TestJsonSetValueJson() public void TestJsonSetJson()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
// Single quoted token case // Single quoted token case
// { {
// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
//
// int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun", "'Times'"); int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "'Times'");
// Assert.That(result, Is.EqualTo(1)); Assert.That(result, Is.EqualTo(1));
//
// string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
// Assert.That(value, Is.EqualTo("Times")); Assert.That(value, Is.EqualTo("Times"));
// } }
// Sub-tree case // Sub-tree case
{ {
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun", "{ 'Filled' : 'Times' }"); int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "{ 'Filled' : 'Times' }");
Assert.That(result, Is.EqualTo(1)); Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Filled"); string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Filled");
@ -394,7 +716,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
{ {
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun", "Times"); int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "Times");
Assert.That(result, Is.EqualTo(0)); Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
@ -405,7 +727,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
{ {
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun.Circus", "'Times'"); int result = (int)InvokeOp("JsonSetJson", storeId, "Fun.Circus", "'Times'");
Assert.That(result, Is.EqualTo(0)); Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus"); string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus");
@ -415,7 +737,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
// Test with fake store // Test with fake store
{ {
UUID fakeStoreId = TestHelpers.ParseTail(0x500); UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int fakeStoreValueSet = (int)InvokeOp("JsonSetValueJson", fakeStoreId, "Hello", "'World'"); int fakeStoreValueSet = (int)InvokeOp("JsonSetJson", fakeStoreId, "Hello", "'World'");
Assert.That(fakeStoreValueSet, Is.EqualTo(0)); Assert.That(fakeStoreValueSet, Is.EqualTo(0));
} }
} }

View File

@ -225,9 +225,10 @@ public enum CollisionFlags : uint
CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
// Following used by BulletSim to control collisions and updates // Following used by BulletSim to control collisions and updates
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed
BS_FLOATS_ON_WATER = 1 << 11, BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level
BS_VEHICLE_COLLISIONS = 1 << 12, BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking
BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape
BS_NONE = 0, BS_NONE = 0,
BS_ALL = 0xFFFFFFFF BS_ALL = 0xFFFFFFFF
}; };

View File

@ -83,7 +83,7 @@ public sealed class BSCharacter : BSPhysObject
_velocity = OMV.Vector3.Zero; _velocity = OMV.Vector3.Zero;
_buoyancy = ComputeBuoyancyFromFlying(isFlying); _buoyancy = ComputeBuoyancyFromFlying(isFlying);
Friction = BSParam.AvatarStandingFriction; Friction = BSParam.AvatarStandingFriction;
Density = BSParam.AvatarDensity; Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor;
// Old versions of ScenePresence passed only the height. If width and/or depth are zero, // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
// replace with the default values. // replace with the default values.
@ -231,6 +231,15 @@ public sealed class BSCharacter : BSPhysObject
PhysicsScene.PE.SetFriction(PhysBody, Friction); PhysicsScene.PE.SetFriction(PhysBody, Friction);
} }
} }
else
{
if (Flying)
{
// Flying and not collising and velocity nearly zero.
ZeroMotion(true /* inTaintTime */);
}
}
DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding); DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding);
} }
else else
@ -274,7 +283,7 @@ public sealed class BSCharacter : BSPhysObject
// This test is done if moving forward, not flying and is colliding with something. // This test is done if moving forward, not flying and is colliding with something.
// DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}", // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
// LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count); // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
if (IsColliding && !Flying && TargetSpeed > 0.1f /* && ForwardSpeed < 0.1f */) if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
{ {
// The range near the character's feet where we will consider stairs // The range near the character's feet where we will consider stairs
float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f; float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
@ -869,7 +878,7 @@ public sealed class BSCharacter : BSPhysObject
* Math.Min(Size.X, Size.Y) / 2 * Math.Min(Size.X, Size.Y) / 2
* Size.Y / 2f // plus the volume of the capsule end caps * Size.Y / 2f // plus the volume of the capsule end caps
); );
_mass = Density * _avatarVolume; _mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
} }
// The physics engine says that properties have updated. Update same and inform // The physics engine says that properties have updated. Update same and inform

View File

@ -127,6 +127,8 @@ public abstract class BSLinkset
m_children = new HashSet<BSPrimLinkable>(); m_children = new HashSet<BSPrimLinkable>();
LinksetMass = parent.RawMass; LinksetMass = parent.RawMass;
Rebuilding = false; Rebuilding = false;
parent.ClearDisplacement();
} }
// Link to a linkset where the child knows the parent. // Link to a linkset where the child knows the parent.
@ -280,6 +282,7 @@ public abstract class BSLinkset
return mass; return mass;
} }
// Computes linkset's center of mass in world coordinates.
protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
{ {
OMV.Vector3 com; OMV.Vector3 com;

View File

@ -93,7 +93,8 @@ public sealed class BSLinksetCompound : BSLinkset
{ {
private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) : base(scene, parent) public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
: base(scene, parent)
{ {
} }
@ -217,59 +218,45 @@ public sealed class BSLinksetCompound : BSLinkset
// and that is caused by us updating the object. // and that is caused by us updating the object.
if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
{ {
// Gather the child info. It might not be there if the linkset is in transition.
BSLinksetCompoundInfo lsi = updated.LinksetInfo as BSLinksetCompoundInfo;
if (lsi != null)
{
// Since the child moved or rotationed, it needs a new relative position within the linkset
BSLinksetCompoundInfo newLsi = new BSLinksetCompoundInfo(lsi.Index, LinksetRoot, updated, OMV.Vector3.Zero);
updated.LinksetInfo = newLsi;
// Find the physical instance of the child // Find the physical instance of the child
if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape))
{
// It is possible that the linkset is still under construction and the child is not yet
// inserted into the compound shape. A rebuild of the linkset in a pre-step action will
// build the whole thing with the new position or rotation.
// The index must be checked because Bullet references the child array but does no validity
// checking of the child index passed.
int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape);
if (updated.LinksetChildIndex < numLinksetChildren)
{ {
// It is possible that the linkset is still under construction and the child is not yet BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex);
// inserted into the compound shape. A rebuild of the linkset in a pre-step action will if (linksetChildShape.HasPhysicalShape)
// build the whole thing with the new position or rotation.
// The index must be checked because Bullet references the child array but does no validity
// checking of the child index passed.
int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape);
if (lsi.Index < numLinksetChildren)
{ {
BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, lsi.Index); // Found the child shape within the compound shape
if (linksetChildShape.HasPhysicalShape) PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex,
{ updated.RawPosition - LinksetRoot.RawPosition,
// Found the child shape within the compound shape updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, lsi.Index, true /* shouldRecalculateLocalAabb */);
newLsi.OffsetFromCenterOfMass, updatedChild = true;
newLsi.OffsetRot, DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
true /* shouldRecalculateLocalAabb */); updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
updatedChild = true;
DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},newLsi={2}",
updated.LocalID, whichUpdated, newLsi);
}
else // DEBUG DEBUG
{ // DEBUG DEBUG
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
updated.LocalID, linksetChildShape);
} // DEBUG DEBUG
} }
else // DEBUG DEBUG else // DEBUG DEBUG
{ // DEBUG DEBUG { // DEBUG DEBUG
// the child is not yet in the compound shape. This is non-fatal. DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}", updated.LocalID, linksetChildShape);
updated.LocalID, numLinksetChildren, lsi.Index);
} // DEBUG DEBUG } // DEBUG DEBUG
} }
else // DEBUG DEBUG else // DEBUG DEBUG
{ // DEBUG DEBUG { // DEBUG DEBUG
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID); // the child is not yet in the compound shape. This is non-fatal.
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
} // DEBUG DEBUG } // DEBUG DEBUG
} }
else // DEBUG DEBUG else // DEBUG DEBUG
{ // DEBUG DEBUG { // DEBUG DEBUG
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noLinkSetInfo,rootPhysShape={1}", DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
updated.LocalID, LinksetRoot.PhysShape);
} // DEBUG DEBUG } // DEBUG DEBUG
if (!updatedChild) if (!updatedChild)
@ -379,6 +366,8 @@ public sealed class BSLinksetCompound : BSLinkset
// Safe to call even if the child is not really in the linkset. // Safe to call even if the child is not really in the linkset.
protected override void RemoveChildFromLinkset(BSPrimLinkable child) protected override void RemoveChildFromLinkset(BSPrimLinkable child)
{ {
child.ClearDisplacement();
if (m_children.Remove(child)) if (m_children.Remove(child))
{ {
DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
@ -424,30 +413,31 @@ public sealed class BSLinksetCompound : BSLinkset
// The center of mass for the linkset is the geometric center of the group. // The center of mass for the linkset is the geometric center of the group.
// Compute a displacement for each component so it is relative to the center-of-mass. // Compute a displacement for each component so it is relative to the center-of-mass.
// Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
OMV.Vector3 centerOfMass; OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition;
OMV.Vector3 centerDisplacement = OMV.Vector3.Zero; if (!disableCOM) // DEBUG DEBUG
if (disableCOM) // DEBUG DEBUG
{ // DEBUG DEBUG
centerOfMass = LinksetRoot.RawPosition; // DEBUG DEBUG
// LinksetRoot.PositionDisplacement = OMV.Vector3.Zero;
} // DEBUG DEBUG
else
{ {
centerOfMass = ComputeLinksetCenterOfMass(); // Compute a center-of-mass in world coordinates.
// 'centerDisplacement' is the value to *add* to all the shape offsets centerOfMassW = ComputeLinksetCenterOfMass();
centerDisplacement = LinksetRoot.RawPosition - centerOfMass;
// Since we're displacing the center of the shape, we need to move the body in the world
// LinksetRoot.PositionDisplacement = centerDisplacement;
// This causes the root prim position to be set properly based on the new PositionDisplacement
LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
// Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0, -centerDisplacement, OMV.Quaternion.Identity, false);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
LinksetRoot.LocalID, centerOfMass, LinksetRoot.RawPosition, centerDisplacement);
} }
OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
// 'centerDisplacement' is the value to subtract from children to give physical offset position
OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement);
// This causes the physical position of the root prim to be offset to accomodate for the displacements
LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
// Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */,
-centerDisplacement,
OMV.Quaternion.Identity, // LinksetRoot.RawOrientation,
false /* shouldRecalculateLocalAabb (is done later after linkset built) */);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
@ -455,38 +445,33 @@ public sealed class BSLinksetCompound : BSLinkset
int memberIndex = 1; int memberIndex = 1;
ForEachMember(delegate(BSPrimLinkable cPrim) ForEachMember(delegate(BSPrimLinkable cPrim)
{ {
if (!IsRoot(cPrim)) if (IsRoot(cPrim))
{ {
// Compute the displacement of the child from the root of the linkset. cPrim.LinksetChildIndex = 0;
// This info is saved in the child prim so the relationship does not }
// change over time and the new child position can be computed else
// when the linkset is being disassembled (the linkset may have moved). {
BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; cPrim.LinksetChildIndex = memberIndex;
if (lci == null)
{
lci = new BSLinksetCompoundInfo(memberIndex, LinksetRoot, cPrim, centerDisplacement);
cPrim.LinksetInfo = lci;
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
}
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},lci={3}",
LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci);
if (cPrim.PhysShape.isNativeShape) if (cPrim.PhysShape.isNativeShape)
{ {
// A native shape is turned into a hull collision shape because native // A native shape is turned into a hull collision shape because native
// shapes are not shared so we have to hullify it so it will be tracked // shapes are not shared so we have to hullify it so it will be tracked
// and freed at the correct time. This also solves the scaling problem // and freed at the correct time. This also solves the scaling problem
// (native shapes scaled but hull/meshes are assumed to not be). // (native shapes scale but hull/meshes are assumed to not be).
// TODO: decide of the native shape can just be used in the compound shape. // TODO: decide of the native shape can just be used in the compound shape.
// Use call to CreateGeomNonSpecial(). // Use call to CreateGeomNonSpecial().
BulletShape saveShape = cPrim.PhysShape; BulletShape saveShape = cPrim.PhysShape;
cPrim.PhysShape.Clear(); // Don't let the create free the child's shape cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
// PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
BulletShape newShape = cPrim.PhysShape; BulletShape newShape = cPrim.PhysShape;
cPrim.PhysShape = saveShape; cPrim.PhysShape = saveShape;
PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetFromCenterOfMass, lci.OffsetRot);
OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
} }
else else
{ {
@ -498,9 +483,13 @@ public sealed class BSLinksetCompound : BSLinkset
PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
} }
PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetFromCenterOfMass, lci.OffsetRot); OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
} }
lci.Index = memberIndex;
memberIndex++; memberIndex++;
} }
return false; // 'false' says to move onto the next child in the list return false; // 'false' says to move onto the next child in the list
@ -509,12 +498,16 @@ public sealed class BSLinksetCompound : BSLinkset
// With all of the linkset packed into the root prim, it has the mass of everyone. // With all of the linkset packed into the root prim, it has the mass of everyone.
LinksetMass = ComputeLinksetMass(); LinksetMass = ComputeLinksetMass();
LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
// Enable the physical position updator to return the position and rotation of the root shape
PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
} }
finally finally
{ {
Rebuilding = false; Rebuilding = false;
} }
// See that the Aabb surrounds the new shape
PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
} }
} }

View File

@ -49,6 +49,7 @@ public static class BSParam
public static float MaxLinearVelocity { get; private set; } public static float MaxLinearVelocity { get; private set; }
public static float MaxAngularVelocity { get; private set; } public static float MaxAngularVelocity { get; private set; }
public static float MaxAddForceMagnitude { get; private set; } public static float MaxAddForceMagnitude { get; private set; }
public static float DensityScaleFactor { get; private set; }
public static float LinearDamping { get; private set; } public static float LinearDamping { get; private set; }
public static float AngularDamping { get; private set; } public static float AngularDamping { get; private set; }
@ -281,29 +282,35 @@ public static class BSParam
new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
0.0001f, 0.0001f,
(s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); }, (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
(s) => { return (float)MinimumObjectMass; }, (s) => { return MinimumObjectMass; },
(s,p,l,v) => { MinimumObjectMass = v; } ), (s,p,l,v) => { MinimumObjectMass = v; } ),
new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
10000.01f, 10000.01f,
(s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); }, (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
(s) => { return (float)MaximumObjectMass; }, (s) => { return MaximumObjectMass; },
(s,p,l,v) => { MaximumObjectMass = v; } ), (s,p,l,v) => { MaximumObjectMass = v; } ),
new ParameterDefn("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object", new ParameterDefn("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object",
1000.0f, 1000.0f,
(s,cf,p,v) => { MaxLinearVelocity = cf.GetFloat(p, v); }, (s,cf,p,v) => { MaxLinearVelocity = cf.GetFloat(p, v); },
(s) => { return (float)MaxLinearVelocity; }, (s) => { return MaxLinearVelocity; },
(s,p,l,v) => { MaxLinearVelocity = v; } ), (s,p,l,v) => { MaxLinearVelocity = v; } ),
new ParameterDefn("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object", new ParameterDefn("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object",
1000.0f, 1000.0f,
(s,cf,p,v) => { MaxAngularVelocity = cf.GetFloat(p, v); }, (s,cf,p,v) => { MaxAngularVelocity = cf.GetFloat(p, v); },
(s) => { return (float)MaxAngularVelocity; }, (s) => { return MaxAngularVelocity; },
(s,p,l,v) => { MaxAngularVelocity = v; } ), (s,p,l,v) => { MaxAngularVelocity = v; } ),
// LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject
new ParameterDefn("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)", new ParameterDefn("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)",
20000.0f, 20000.0f,
(s,cf,p,v) => { MaxAddForceMagnitude = cf.GetFloat(p, v); }, (s,cf,p,v) => { MaxAddForceMagnitude = cf.GetFloat(p, v); },
(s) => { return (float)MaxAddForceMagnitude; }, (s) => { return MaxAddForceMagnitude; },
(s,p,l,v) => { MaxAddForceMagnitude = v; } ), (s,p,l,v) => { MaxAddForceMagnitude = v; } ),
// Density is passed around as 100kg/m3. This scales that to 1kg/m3.
new ParameterDefn("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
0.01f,
(s,cf,p,v) => { DensityScaleFactor = cf.GetFloat(p, v); },
(s) => { return DensityScaleFactor; },
(s,p,l,v) => { DensityScaleFactor = v; } ),
new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
2200f, 2200f,

View File

@ -99,6 +99,9 @@ public abstract class BSPhysObject : PhysicsActor
CollisionAccumulation = 0; CollisionAccumulation = 0;
ColliderIsMoving = false; ColliderIsMoving = false;
CollisionScore = 0; CollisionScore = 0;
// All axis free.
LockedAxis = LockedAxisFree;
} }
// Tell the object to clean up. // Tell the object to clean up.
@ -136,6 +139,7 @@ public abstract class BSPhysObject : PhysicsActor
// The objects base shape information. Null if not a prim type shape. // The objects base shape information. Null if not a prim type shape.
public PrimitiveBaseShape BaseShape { get; protected set; } public PrimitiveBaseShape BaseShape { get; protected set; }
// Some types of objects have preferred physical representations. // Some types of objects have preferred physical representations.
// Returns SHAPE_UNKNOWN if there is no preference. // Returns SHAPE_UNKNOWN if there is no preference.
public virtual BSPhysicsShapeType PreferredPhysicalShape public virtual BSPhysicsShapeType PreferredPhysicalShape
@ -150,15 +154,17 @@ public abstract class BSPhysObject : PhysicsActor
public EntityProperties LastEntityProperties { get; set; } public EntityProperties LastEntityProperties { get; set; }
public virtual OMV.Vector3 Scale { get; set; } public virtual OMV.Vector3 Scale { get; set; }
public abstract bool IsSolid { get; }
public abstract bool IsStatic { get; }
public abstract bool IsSelected { get; }
// It can be confusing for an actor to know if it should move or update an object // It can be confusing for an actor to know if it should move or update an object
// depeneding on the setting of 'selected', 'physical, ... // depeneding on the setting of 'selected', 'physical, ...
// This flag is the true test -- if true, the object is being acted on in the physical world // This flag is the true test -- if true, the object is being acted on in the physical world
public abstract bool IsPhysicallyActive { get; } public abstract bool IsPhysicallyActive { get; }
// Detailed state of the object.
public abstract bool IsSolid { get; }
public abstract bool IsStatic { get; }
public abstract bool IsSelected { get; }
// Materialness // Materialness
public MaterialAttributes.Material Material { get; private set; } public MaterialAttributes.Material Material { get; private set; }
public override void SetMaterial(int material) public override void SetMaterial(int material)
@ -169,7 +175,8 @@ public abstract class BSPhysObject : PhysicsActor
MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
Friction = matAttrib.friction; Friction = matAttrib.friction;
Restitution = matAttrib.restitution; Restitution = matAttrib.restitution;
Density = matAttrib.density; Density = matAttrib.density / BSParam.DensityScaleFactor;
DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
} }
// Stop all physical motion. // Stop all physical motion.
@ -185,14 +192,6 @@ public abstract class BSPhysObject : PhysicsActor
public abstract OMV.Quaternion RawOrientation { get; set; } public abstract OMV.Quaternion RawOrientation { get; set; }
public abstract OMV.Quaternion ForceOrientation { get; set; } public abstract OMV.Quaternion ForceOrientation { get; set; }
public virtual float TargetSpeed
{
get
{
OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
return characterOrientedVelocity.X;
}
}
public abstract OMV.Vector3 RawVelocity { get; set; } public abstract OMV.Vector3 RawVelocity { get; set; }
public abstract OMV.Vector3 ForceVelocity { get; set; } public abstract OMV.Vector3 ForceVelocity { get; set; }
@ -202,6 +201,7 @@ public abstract class BSPhysObject : PhysicsActor
public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
// The current velocity forward
public virtual float ForwardSpeed public virtual float ForwardSpeed
{ {
get get
@ -210,6 +210,22 @@ public abstract class BSPhysObject : PhysicsActor
return characterOrientedVelocity.X; return characterOrientedVelocity.X;
} }
} }
// The forward speed we are trying to achieve (TargetVelocity)
public virtual float TargetVelocitySpeed
{
get
{
OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
return characterOrientedVelocity.X;
}
}
// The user can optionally set the center of mass. The user's setting will override any
// computed center-of-mass (like in linksets).
public OMV.Vector3? UserSetCenterOfMass { get; set; }
public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free.
public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free
#region Collisions #region Collisions
@ -407,9 +423,7 @@ public abstract class BSPhysObject : PhysicsActor
{ {
// Clean out any existing action // Clean out any existing action
UnRegisterPreStepAction(op, id); UnRegisterPreStepAction(op, id);
RegisteredPrestepActions[identifier] = actn; RegisteredPrestepActions[identifier] = actn;
PhysicsScene.BeforeStep += actn; PhysicsScene.BeforeStep += actn;
} }
DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
@ -455,9 +469,7 @@ public abstract class BSPhysObject : PhysicsActor
{ {
// Clean out any existing action // Clean out any existing action
UnRegisterPostStepAction(op, id); UnRegisterPostStepAction(op, id);
RegisteredPoststepActions[identifier] = actn; RegisteredPoststepActions[identifier] = actn;
PhysicsScene.AfterStep += actn; PhysicsScene.AfterStep += actn;
} }
DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier); DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
@ -494,7 +506,58 @@ public abstract class BSPhysObject : PhysicsActor
} }
DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID); DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
} }
// When an update to the physical properties happens, this event is fired to let
// different actors to modify the update before it is passed around
public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
public event PreUpdatePropertyAction OnPreUpdateProperty;
protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
{
PreUpdatePropertyAction actions = OnPreUpdateProperty;
if (actions != null)
actions(ref entprop);
}
private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>();
public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn)
{
lock (RegisteredPreUpdatePropertyActions)
{
// Clean out any existing action
UnRegisterPreUpdatePropertyAction(identifier);
RegisteredPreUpdatePropertyActions[identifier] = actn;
OnPreUpdateProperty += actn;
}
DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier);
}
public bool UnRegisterPreUpdatePropertyAction(string identifier)
{
bool removed = false;
lock (RegisteredPreUpdatePropertyActions)
{
if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier))
{
OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier];
RegisteredPreUpdatePropertyActions.Remove(identifier);
removed = true;
}
}
DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed);
return removed;
}
public void UnRegisterAllPreUpdatePropertyActions()
{
lock (RegisteredPreUpdatePropertyActions)
{
foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions)
{
OnPreUpdateProperty -= kvp.Value;
}
RegisteredPreUpdatePropertyActions.Clear();
}
DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID);
}
#endregion // Per Simulation Step actions #endregion // Per Simulation Step actions
// High performance detailed logging routine used by the physical objects. // High performance detailed logging routine used by the physical objects.

View File

@ -242,6 +242,45 @@ public class BSPrim : BSPhysObject
public override void LockAngularMotion(OMV.Vector3 axis) public override void LockAngularMotion(OMV.Vector3 axis)
{ {
DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f);
if (axis.X != 1) locking.X = 0f;
if (axis.Y != 1) locking.Y = 0f;
if (axis.Z != 1) locking.Z = 0f;
LockedAxis = locking;
/* Not implemented yet
if (LockedAxis != LockedAxisFree)
{
// Something is locked so start the thingy that keeps that axis from changing
RegisterPreUpdatePropertyAction("BSPrim.LockAngularMotion", delegate(ref EntityProperties entprop)
{
if (LockedAxis != LockedAxisFree)
{
if (IsPhysicallyActive)
{
// Bullet can lock axis but it only works for global axis.
// Check if this prim is aligned on global axis and use Bullet's
// system if so.
ForceOrientation = entprop.Rotation;
ForceRotationalVelocity = entprop.RotationalVelocity;
}
}
else
{
UnRegisterPreUpdatePropertyAction("BSPrim.LockAngularMotion");
}
});
}
else
{
// Everything seems unlocked
UnRegisterPreUpdatePropertyAction("BSPrim.LockAngularMotion");
}
*/
return; return;
} }
@ -311,7 +350,8 @@ public class BSPrim : BSPhysObject
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
OMV.Vector3 upForce = OMV.Vector3.Zero; OMV.Vector3 upForce = OMV.Vector3.Zero;
if (RawPosition.Z < terrainHeight) float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
{ {
DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
float targetHeight = terrainHeight + (Size.Z / 2f); float targetHeight = terrainHeight + (Size.Z / 2f);
@ -442,7 +482,7 @@ public class BSPrim : BSPhysObject
RegisterPreStepAction("BSPrim.setForce", LocalID, RegisterPreStepAction("BSPrim.setForce", LocalID,
delegate(float timeStep) delegate(float timeStep)
{ {
if (!IsPhysicallyActive) if (!IsPhysicallyActive || _force == OMV.Vector3.Zero)
{ {
UnRegisterPreStepAction("BSPrim.setForce", LocalID); UnRegisterPreStepAction("BSPrim.setForce", LocalID);
return; return;
@ -576,6 +616,8 @@ public class BSPrim : BSPhysObject
} }
} }
} }
// The simulator/viewer keep density as 100kg/m3.
// Remember to use BSParam.DensityScaleFactor to create the physical density.
public override float Density public override float Density
{ {
get { return base.Density; } get { return base.Density; }
@ -647,7 +689,7 @@ public class BSPrim : BSPhysObject
RegisterPreStepAction("BSPrim.setTorque", LocalID, RegisterPreStepAction("BSPrim.setTorque", LocalID,
delegate(float timeStep) delegate(float timeStep)
{ {
if (!IsPhysicallyActive) if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero)
{ {
UnRegisterPreStepAction("BSPrim.setTorque", LocalID); UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
return; return;
@ -1569,7 +1611,8 @@ public class BSPrim : BSPhysObject
profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
volume *= (profileEnd - profileBegin); volume *= (profileEnd - profileBegin);
returnMass = Density * volume; returnMass = Density * BSParam.DensityScaleFactor * volume;
DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
@ -1607,6 +1650,8 @@ public class BSPrim : BSPhysObject
// the world that things have changed. // the world that things have changed.
public override void UpdateProperties(EntityProperties entprop) public override void UpdateProperties(EntityProperties entprop)
{ {
TriggerPreUpdatePropertyAction(ref entprop);
// A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
// TODO: handle physics introduced by Bullet with computed vehicle physics. // TODO: handle physics introduced by Bullet with computed vehicle physics.
if (VehicleController.IsActive) if (VehicleController.IsActive)
@ -1619,7 +1664,11 @@ public class BSPrim : BSPhysObject
// Assign directly to the local variables so the normal set actions do not happen // Assign directly to the local variables so the normal set actions do not happen
_position = entprop.Position; _position = entprop.Position;
_orientation = entprop.Rotation; _orientation = entprop.Rotation;
_velocity = entprop.Velocity; // _velocity = entprop.Velocity;
// DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
// very sensitive to velocity changes.
if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f))
_velocity = entprop.Velocity;
_acceleration = entprop.Acceleration; _acceleration = entprop.Acceleration;
_rotationalVelocity = entprop.RotationalVelocity; _rotationalVelocity = entprop.RotationalVelocity;

View File

@ -44,72 +44,107 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public class BSPrimDisplaced : BSPrim public class BSPrimDisplaced : BSPrim
{ {
// 'Position' and 'Orientation' is what the simulator thinks the positions of the prim is. // The purpose of this module is to do any mapping between what the simulator thinks
// Because Bullet needs the zero coordinate to be the center of mass of the linkset, // the prim position and orientation is and what the physical position/orientation.
// sometimes it is necessary to displace the position the physics engine thinks // This difference happens because Bullet assumes the center-of-mass is the <0,0,0>
// the position is. PositionDisplacement must be added and removed from the // of the prim/linkset. The simulator tracks the location of the prim/linkset by
// position as the simulator position is stored and fetched from the physics // the location of the root prim. So, if center-of-mass is anywhere but the origin
// engine. Similar to OrientationDisplacement. // of the root prim, the physical origin is displaced from the simulator origin.
//
// This routine works by capturing the Force* setting of position/orientation/... and
// adjusting the simulator values (being set) into the physical values.
// The conversion is also done in the opposite direction (physical origin -> simulator origin).
//
// The updateParameter call is also captured and the values from the physics engine
// are converted into simulator origin values before being passed to the base
// class.
public virtual OMV.Vector3 PositionDisplacement { get; set; } public virtual OMV.Vector3 PositionDisplacement { get; set; }
public virtual OMV.Quaternion OrientationDisplacement { get; set; } public virtual OMV.Quaternion OrientationDisplacement { get; set; }
public virtual OMV.Vector3 CenterOfMassLocation { get; set; }
public virtual OMV.Vector3 GeometricCenterLocation { get; set; }
public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
: base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
{ {
CenterOfMassLocation = RawPosition; ClearDisplacement();
GeometricCenterLocation = RawPosition; }
public void ClearDisplacement()
{
PositionDisplacement = OMV.Vector3.Zero;
OrientationDisplacement = OMV.Quaternion.Identity;
}
// Set this sets and computes the displacement from the passed prim to the center-of-mass.
// A user set value for center-of-mass overrides whatever might be passed in here.
// The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement)
{
Vector3 comDisp;
if (UserSetCenterOfMass.HasValue)
comDisp = (OMV.Vector3)UserSetCenterOfMass;
else
comDisp = centerOfMassDisplacement;
if (comDisp == Vector3.Zero)
{
// If there is no diplacement. Things get reset.
PositionDisplacement = OMV.Vector3.Zero;
OrientationDisplacement = OMV.Quaternion.Identity;
}
else
{
// Remember the displacement from root as well as the origional rotation of the
// new center-of-mass.
PositionDisplacement = comDisp;
OrientationDisplacement = OMV.Quaternion.Identity;
}
} }
public override Vector3 ForcePosition public override Vector3 ForcePosition
{ {
get get { return base.ForcePosition; }
{
return base.ForcePosition;
}
set set
{ {
base.ForcePosition = value; if (PositionDisplacement != OMV.Vector3.Zero)
CenterOfMassLocation = RawPosition; base.ForcePosition = value - (PositionDisplacement * RawOrientation);
GeometricCenterLocation = RawPosition; else
base.ForcePosition = value;
} }
} }
public override Quaternion ForceOrientation public override Quaternion ForceOrientation
{ {
get get { return base.ForceOrientation; }
{
return base.ForceOrientation;
}
set set
{ {
base.ForceOrientation = value; base.ForceOrientation = value;
} }
} }
// TODO: decide if this is the right place for these variables.
// Somehow incorporate the optional settability by the user.
// Is this used? // Is this used?
public override OMV.Vector3 CenterOfMass public override OMV.Vector3 CenterOfMass
{ {
get { return CenterOfMassLocation; } get { return RawPosition; }
} }
// Is this used? // Is this used?
public override OMV.Vector3 GeometricCenter public override OMV.Vector3 GeometricCenter
{ {
get { return GeometricCenterLocation; } get { return RawPosition; }
} }
public override void UpdateProperties(EntityProperties entprop) public override void UpdateProperties(EntityProperties entprop)
{ {
// Undo any center-of-mass displacement that might have been done. // Undo any center-of-mass displacement that might have been done.
if (PositionDisplacement != OMV.Vector3.Zero) if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity)
{ {
// Correct for any rotation around the center-of-mass // Correct for any rotation around the center-of-mass
// TODO!!! // TODO!!!
entprop.Position -= PositionDisplacement; entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation);
// entprop.Rotation = something;
} }
base.UpdateProperties(entprop); base.UpdateProperties(entprop);

View File

@ -38,6 +38,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
public class BSPrimLinkable : BSPrimDisplaced public class BSPrimLinkable : BSPrimDisplaced
{ {
public BSLinkset Linkset { get; set; } public BSLinkset Linkset { get; set; }
// The index of this child prim.
public int LinksetChildIndex { get; set; }
public BSLinksetInfo LinksetInfo { get; set; } public BSLinksetInfo LinksetInfo { get; set; }
public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
@ -90,7 +93,6 @@ public class BSPrimLinkable : BSPrimDisplaced
DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
return; return;
base.delink();
} }
// When simulator changes position, this might be moving a child of the linkset. // When simulator changes position, this might be moving a child of the linkset.
@ -133,7 +135,8 @@ public class BSPrimLinkable : BSPrimDisplaced
// When going from non-physical to physical, this re-enables the constraints that // When going from non-physical to physical, this re-enables the constraints that
// had been automatically disabled when the mass was set to zero. // had been automatically disabled when the mass was set to zero.
// For compound based linksets, this enables and disables interactions of the children. // For compound based linksets, this enables and disables interactions of the children.
Linkset.Refresh(this); if (Linkset != null) // null can happen during initialization
Linkset.Refresh(this);
} }
protected override void MakeDynamic(bool makeStatic) protected override void MakeDynamic(bool makeStatic)

View File

@ -52,7 +52,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
{ {
bool Cancel(); bool Cancel();
void Abort(); void Abort();
bool Wait(TimeSpan t);
/// <summary>
/// Wait for the work item to complete.
/// </summary>
/// <param name='t'>The number of milliseconds to wait. Must be >= -1 (Timeout.Infinite).</param>
bool Wait(int t);
} }
/// <summary> /// <summary>

View File

@ -4479,6 +4479,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
} }
} }
} }
if (pushAllowed) if (pushAllowed)
{ {
float distance = (PusheePos - m_host.AbsolutePosition).Length(); float distance = (PusheePos - m_host.AbsolutePosition).Length();
@ -4507,17 +4508,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
applied_linear_impulse *= scaling_factor; applied_linear_impulse *= scaling_factor;
} }
if (pusheeIsAvatar) if (pusheeIsAvatar)
{ {
if (pusheeav != null) if (pusheeav != null)
{ {
if (pusheeav.PhysicsActor != null) PhysicsActor pa = pusheeav.PhysicsActor;
if (pa != null)
{ {
if (local != 0) if (local != 0)
{ {
applied_linear_impulse *= m_host.GetWorldRotation(); applied_linear_impulse *= m_host.GetWorldRotation();
} }
pusheeav.PhysicsActor.AddForce(applied_linear_impulse, true);
pa.AddForce(applied_linear_impulse, true);
} }
} }
} }

View File

@ -595,7 +595,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
if (!m_coopTermination) if (!m_coopTermination)
{ {
// If we're not co-operative terminating then try and wait for the event to complete before stopping // 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))) if (workItem.Wait(timeout))
return true; return true;
} }
else else
@ -610,7 +610,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
// For now, we will wait forever since the event should always cleanly terminate once LSL loop // 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. // checking is implemented. May want to allow a shorter timeout option later.
if (workItem.Wait(TimeSpan.MaxValue)) if (workItem.Wait(Timeout.Infinite))
{ {
if (DebugLevel >= 1) if (DebugLevel >= 1)
m_log.DebugFormat( m_log.DebugFormat(

View File

@ -57,8 +57,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
wr.Abort(); wr.Abort();
} }
public bool Wait(TimeSpan t) public bool Wait(int t)
{ {
// We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the
// TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an
// int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8
// (or very likely other versions of Mono at least up until 3.0.3).
return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false);
} }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.