aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs27
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs14
-rw-r--r--OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs15
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs6
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs55
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs76
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs65
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs40
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs446
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs7
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs15
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs3
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs155
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs17
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs97
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs59
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs85
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs7
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs7
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs9
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs6
27 files changed, 983 insertions, 242 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
index cfb1605..bb8825b 100644
--- a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
@@ -535,6 +535,8 @@ namespace OpenSim.Framework.Servers.HttpServer
535 /// <param name="message"></param> 535 /// <param name="message"></param>
536 public void Close(string message) 536 public void Close(string message)
537 { 537 {
538 if (_networkContext == null)
539 return;
538 if (_networkContext.Stream != null) 540 if (_networkContext.Stream != null)
539 { 541 {
540 if (_networkContext.Stream.CanWrite) 542 if (_networkContext.Stream.CanWrite)
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
index 191bccf..6ef8815 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
@@ -59,6 +59,8 @@ namespace OpenSim.Region.ClientStack.Linden
59// private static readonly ILog m_log = 59// private static readonly ILog m_log =
60// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 60// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61 61
62 public event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest;
63
62 private Scene m_scene; 64 private Scene m_scene;
63 65
64 /// <summary> 66 /// <summary>
@@ -94,6 +96,8 @@ namespace OpenSim.Region.ClientStack.Linden
94 { 96 {
95 m_scene = s; 97 m_scene = s;
96 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 98 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
99
100 m_scene.RegisterModuleInterface<ISimulatorFeaturesModule>(this);
97 } 101 }
98 102
99 public void RemoveRegion(Scene s) 103 public void RemoveRegion(Scene s)
@@ -156,7 +160,7 @@ namespace OpenSim.Region.ClientStack.Linden
156 IRequestHandler reqHandler 160 IRequestHandler reqHandler
157 = new RestHTTPHandler( 161 = new RestHTTPHandler(
158 "GET", "/CAPS/" + UUID.Random(), 162 "GET", "/CAPS/" + UUID.Random(),
159 HandleSimulatorFeaturesRequest, "SimulatorFeatures", agentID.ToString()); 163 x => { return HandleSimulatorFeaturesRequest(x, agentID); }, "SimulatorFeatures", agentID.ToString());
160 164
161 caps.RegisterHandler("SimulatorFeatures", reqHandler); 165 caps.RegisterHandler("SimulatorFeatures", reqHandler);
162 } 166 }
@@ -185,18 +189,33 @@ namespace OpenSim.Region.ClientStack.Linden
185 return new OSDMap(m_features); 189 return new OSDMap(m_features);
186 } 190 }
187 191
188 private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod) 192 private OSDMap DeepCopy()
193 {
194 // This isn't the cheapest way of doing this but the rate
195 // of occurrence is low (on sim entry only) and it's a sure
196 // way to get a true deep copy.
197 OSD copy = OSDParser.DeserializeLLSDXml(OSDParser.SerializeLLSDXmlString(m_features));
198
199 return (OSDMap)copy;
200 }
201
202 private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod, UUID agentID)
189 { 203 {
190// m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request"); 204// m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request");
191 205
206 OSDMap copy = DeepCopy();
207
208 SimulatorFeaturesRequestDelegate handlerOnSimulatorFeaturesRequest = OnSimulatorFeaturesRequest;
209 if (handlerOnSimulatorFeaturesRequest != null)
210 handlerOnSimulatorFeaturesRequest(agentID, ref copy);
211
192 //Send back data 212 //Send back data
193 Hashtable responsedata = new Hashtable(); 213 Hashtable responsedata = new Hashtable();
194 responsedata["int_response_code"] = 200; 214 responsedata["int_response_code"] = 200;
195 responsedata["content_type"] = "text/plain"; 215 responsedata["content_type"] = "text/plain";
196 responsedata["keepalive"] = false; 216 responsedata["keepalive"] = false;
197 217
198 lock (m_features) 218 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(copy);
199 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(m_features);
200 219
201 return responsedata; 220 return responsedata;
202 } 221 }
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
index d1ad74f..b67c0df 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
42 public class AssetTransactionModule : INonSharedRegionModule, 42 public class AssetTransactionModule : INonSharedRegionModule,
43 IAgentAssetTransactions 43 IAgentAssetTransactions
44 { 44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 46
47 protected Scene m_Scene; 47 protected Scene m_Scene;
48 private bool m_dumpAssetsToFile = false; 48 private bool m_dumpAssetsToFile = false;
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs
index d36f65a..37131b9 100644
--- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs
@@ -44,7 +44,7 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")] 44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")]
45 public class DAExampleModule : INonSharedRegionModule 45 public class DAExampleModule : INonSharedRegionModule
46 { 46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 private static readonly bool ENABLED = false; // enable for testing 49 private static readonly bool ENABLED = false; // enable for testing
50 50
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
index fb74cc6..f3436d1 100644
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
@@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
57 try 57 try
58 { 58 {
59 IConfig statConfig = source.Configs["Statistics.Binary"]; 59 IConfig statConfig = source.Configs["Statistics.Binary"];
60 if (statConfig.Contains("enabled") && statConfig.GetBoolean("enabled")) 60 if (statConfig != null && statConfig.Contains("enabled") && statConfig.GetBoolean("enabled"))
61 { 61 {
62 if (statConfig.Contains("collect_region_stats")) 62 if (statConfig.Contains("collect_region_stats"))
63 { 63 {
diff --git a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs
index 385f5ad..cbffca7 100644
--- a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs
@@ -111,13 +111,15 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC
111 m_rpcPending = new Dictionary<UUID, RPCRequestInfo>(); 111 m_rpcPending = new Dictionary<UUID, RPCRequestInfo>();
112 m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>(); 112 m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>();
113 m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>(); 113 m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>();
114 114 if (config.Configs["XMLRPC"] != null)
115 try
116 {
117 m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort);
118 }
119 catch (Exception)
120 { 115 {
116 try
117 {
118 m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort);
119 }
120 catch (Exception)
121 {
122 }
121 } 123 }
122 } 124 }
123 125
diff --git a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs
index cc7885a..b40d24f 100644
--- a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs
@@ -31,6 +31,16 @@ using OpenMetaverse;
31 31
32namespace OpenSim.Region.Framework.Interfaces 32namespace OpenSim.Region.Framework.Interfaces
33{ 33{
34 // these could be expanded at some point to provide more type information
35 // for now value accounts for all base types
36 public enum JsonStoreNodeType
37 {
38 Undefined = 0,
39 Object = 1,
40 Array = 2,
41 Value = 3
42 }
43
34 public delegate void TakeValueCallback(string s); 44 public delegate void TakeValueCallback(string s);
35 45
36 public interface IJsonStoreModule 46 public interface IJsonStoreModule
@@ -38,13 +48,18 @@ namespace OpenSim.Region.Framework.Interfaces
38 bool AttachObjectStore(UUID objectID); 48 bool AttachObjectStore(UUID objectID);
39 bool CreateStore(string value, ref UUID result); 49 bool CreateStore(string value, ref UUID result);
40 bool DestroyStore(UUID storeID); 50 bool DestroyStore(UUID storeID);
51
52 JsonStoreNodeType GetPathType(UUID storeID, string path);
41 bool TestStore(UUID storeID); 53 bool TestStore(UUID storeID);
42 bool TestPath(UUID storeID, string path, bool useJson); 54 bool TestPath(UUID storeID, string path, bool useJson);
55
43 bool SetValue(UUID storeID, string path, string value, bool useJson); 56 bool SetValue(UUID storeID, string path, string value, bool useJson);
44 bool RemoveValue(UUID storeID, string path); 57 bool RemoveValue(UUID storeID, string path);
45 bool GetValue(UUID storeID, string path, bool useJson, out string value); 58 bool GetValue(UUID storeID, string path, bool useJson, out string value);
46 59
47 void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); 60 void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback);
48 void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); 61 void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback);
62
63 int GetArrayLength(UUID storeID, string path);
49 } 64 }
50} 65}
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs b/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs
index 8cef14e..6effcc1 100644
--- a/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/ISimulatorFeaturesModule.cs
@@ -26,18 +26,22 @@
26 */ 26 */
27 27
28using System; 28using System;
29using OpenMetaverse;
29using OpenMetaverse.StructuredData; 30using OpenMetaverse.StructuredData;
30 31
31namespace OpenSim.Region.Framework.Interfaces 32namespace OpenSim.Region.Framework.Interfaces
32{ 33{
34 public delegate void SimulatorFeaturesRequestDelegate(UUID agentID, ref OSDMap features);
35
33 /// <summary> 36 /// <summary>
34 /// Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures capability. 37 /// Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures capability.
35 /// </summary> 38 /// </summary>
36 public interface ISimulatorFeaturesModule 39 public interface ISimulatorFeaturesModule
37 { 40 {
41 event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest;
38 void AddFeature(string name, OSD value); 42 void AddFeature(string name, OSD value);
39 bool RemoveFeature(string name); 43 bool RemoveFeature(string name);
40 bool TryGetFeature(string name, out OSD value); 44 bool TryGetFeature(string name, out OSD value);
41 OSDMap GetFeatures(); 45 OSDMap GetFeatures();
42 } 46 }
43} \ No newline at end of file 47}
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index 9ee1520..59d0148 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -791,6 +791,19 @@ namespace OpenSim.Region.Framework.Scenes
791 public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj); 791 public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj);
792 792
793 /// <summary> 793 /// <summary>
794 /// Triggered when an object is placed into the physical scene (PhysicsActor created).
795 /// </summary>
796 public event Action<SceneObjectPart> OnObjectAddedToPhysicalScene;
797 /// <summary>
798 /// Triggered when an object is removed from the physical scene (PhysicsActor destroyed).
799 /// </summary>
800 /// <remarks>
801 /// Note: this is triggered just before the PhysicsActor is removed from the
802 /// physics engine so the receiver can do any necessary cleanup before its destruction.
803 /// </remarks>
804 public event Action<SceneObjectPart> OnObjectRemovedFromPhysicalScene;
805
806 /// <summary>
794 /// Triggered when an object is removed from the scene. 807 /// Triggered when an object is removed from the scene.
795 /// </summary> 808 /// </summary>
796 /// <remarks> 809 /// <remarks>
@@ -1516,6 +1529,48 @@ namespace OpenSim.Region.Framework.Scenes
1516 } 1529 }
1517 } 1530 }
1518 1531
1532 public void TriggerObjectAddedToPhysicalScene(SceneObjectPart obj)
1533 {
1534 Action<SceneObjectPart> handler = OnObjectAddedToPhysicalScene;
1535 if (handler != null)
1536 {
1537 foreach (Action<SceneObjectPart> d in handler.GetInvocationList())
1538 {
1539 try
1540 {
1541 d(obj);
1542 }
1543 catch (Exception e)
1544 {
1545 m_log.ErrorFormat(
1546 "[EVENT MANAGER]: Delegate for TriggerObjectAddedToPhysicalScene failed - continuing. {0} {1}",
1547 e.Message, e.StackTrace);
1548 }
1549 }
1550 }
1551 }
1552
1553 public void TriggerObjectRemovedFromPhysicalScene(SceneObjectPart obj)
1554 {
1555 Action<SceneObjectPart> handler = OnObjectRemovedFromPhysicalScene;
1556 if (handler != null)
1557 {
1558 foreach (Action<SceneObjectPart> d in handler.GetInvocationList())
1559 {
1560 try
1561 {
1562 d(obj);
1563 }
1564 catch (Exception e)
1565 {
1566 m_log.ErrorFormat(
1567 "[EVENT MANAGER]: Delegate for TriggerObjectRemovedFromPhysicalScene failed - continuing. {0} {1}",
1568 e.Message, e.StackTrace);
1569 }
1570 }
1571 }
1572 }
1573
1519 public void TriggerShutdown() 1574 public void TriggerShutdown()
1520 { 1575 {
1521 Action handlerShutdown = OnShutdown; 1576 Action handlerShutdown = OnShutdown;
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 9b29973..cce8b21 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -4316,6 +4316,7 @@ namespace OpenSim.Region.Framework.Scenes
4316 } 4316 }
4317 4317
4318 PhysActor = pa; 4318 PhysActor = pa;
4319 ParentGroup.Scene.EventManager.TriggerObjectAddedToPhysicalScene(this);
4319 } 4320 }
4320 4321
4321 /// <summary> 4322 /// <summary>
@@ -4328,6 +4329,7 @@ namespace OpenSim.Region.Framework.Scenes
4328 /// </remarks> 4329 /// </remarks>
4329 public void RemoveFromPhysics() 4330 public void RemoveFromPhysics()
4330 { 4331 {
4332 ParentGroup.Scene.EventManager.TriggerObjectRemovedFromPhysicalScene(this);
4331 ParentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); 4333 ParentGroup.Scene.PhysicsScene.RemovePrim(PhysActor);
4332 PhysActor = null; 4334 PhysActor = null;
4333 } 4335 }
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
index 82a4da7..ca3989a 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
@@ -68,14 +68,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
68 protected List<TakeValueCallbackClass> m_TakeStore; 68 protected List<TakeValueCallbackClass> m_TakeStore;
69 protected List<TakeValueCallbackClass> m_ReadStore; 69 protected List<TakeValueCallbackClass> m_ReadStore;
70 70
71 // add separators for quoted paths 71 // add separators for quoted paths and array references
72 protected static Regex m_ParsePassOne = new Regex("{[^}]+}"); 72 protected static Regex m_ParsePassOne = new Regex("({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])");
73
74 // add separators for array references
75 protected static Regex m_ParsePassTwo = new Regex("(\\[[0-9]+\\]|\\[\\+\\])");
76 73
77 // add quotes to bare identifiers which are limited to alphabetic characters 74 // add quotes to bare identifiers which are limited to alphabetic characters
78 protected static Regex m_ParsePassThree = new Regex("\\.([a-zA-Z]+)"); 75 protected static Regex m_ParsePassThree = new Regex("(?<!{[^}]*)\\.([a-zA-Z]+)(?=\\.)");
79 76
80 // remove extra separator characters 77 // remove extra separator characters
81 protected static Regex m_ParsePassFour = new Regex("\\.+"); 78 protected static Regex m_ParsePassFour = new Regex("\\.+");
@@ -84,7 +81,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
84 protected static Regex m_ValidatePath = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)*$"); 81 protected static Regex m_ValidatePath = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)*$");
85 82
86 // expression used to match path components 83 // expression used to match path components
87 protected static Regex m_PathComponent = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\]+)"); 84 protected static Regex m_PathComponent = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])");
88 85
89 // extract the internals of an array reference 86 // extract the internals of an array reference
90 protected static Regex m_SimpleArrayPattern = new Regex("\\[([0-9]+)\\]"); 87 protected static Regex m_SimpleArrayPattern = new Regex("\\[([0-9]+)\\]");
@@ -131,15 +128,46 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
131 m_TakeStore = new List<TakeValueCallbackClass>(); 128 m_TakeStore = new List<TakeValueCallbackClass>();
132 m_ReadStore = new List<TakeValueCallbackClass>(); 129 m_ReadStore = new List<TakeValueCallbackClass>();
133 } 130 }
134 131
135 public JsonStore(string value) : this() 132 public JsonStore(string value) : this()
136 { 133 {
134 // This is going to throw an exception if the value is not
135 // a valid JSON chunk. Calling routines should catch the
136 // exception and handle it appropriately
137 if (String.IsNullOrEmpty(value)) 137 if (String.IsNullOrEmpty(value))
138 ValueStore = new OSDMap(); 138 ValueStore = new OSDMap();
139 else 139 else
140 ValueStore = OSDParser.DeserializeJson(value); 140 ValueStore = OSDParser.DeserializeJson(value);
141 } 141 }
142
143 // -----------------------------------------------------------------
144 /// <summary>
145 ///
146 /// </summary>
147 // -----------------------------------------------------------------
148 public JsonStoreNodeType PathType(string expr)
149 {
150 Stack<string> path;
151 if (! ParsePathExpression(expr,out path))
152 return JsonStoreNodeType.Undefined;
153
154 OSD result = ProcessPathExpression(ValueStore,path);
142 155
156 if (result == null)
157 return JsonStoreNodeType.Undefined;
158
159 if (result is OSDMap)
160 return JsonStoreNodeType.Object;
161
162 if (result is OSDArray)
163 return JsonStoreNodeType.Array;
164
165 if (OSDBaseType(result.Type))
166 return JsonStoreNodeType.Value;
167
168 return JsonStoreNodeType.Undefined;
169 }
170
143 // ----------------------------------------------------------------- 171 // -----------------------------------------------------------------
144 /// <summary> 172 /// <summary>
145 /// 173 ///
@@ -167,6 +195,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
167 /// 195 ///
168 /// </summary> 196 /// </summary>
169 // ----------------------------------------------------------------- 197 // -----------------------------------------------------------------
198 public int ArrayLength(string expr)
199 {
200 Stack<string> path;
201 if (! ParsePathExpression(expr,out path))
202 return -1;
203
204 OSD result = ProcessPathExpression(ValueStore,path);
205 if (result != null && result.Type == OSDType.Array)
206 {
207 OSDArray arr = result as OSDArray;
208 return arr.Count;
209 }
210
211 return -1;
212 }
213
214 // -----------------------------------------------------------------
215 /// <summary>
216 ///
217 /// </summary>
218 // -----------------------------------------------------------------
170 public bool GetValue(string expr, out string value, bool useJson) 219 public bool GetValue(string expr, out string value, bool useJson)
171 { 220 {
172 Stack<string> path; 221 Stack<string> path;
@@ -462,11 +511,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
462 // add front and rear separators 511 // add front and rear separators
463 expr = "." + expr + "."; 512 expr = "." + expr + ".";
464 513
465 // add separators for quoted exprs 514 // add separators for quoted exprs and array references
466 expr = m_ParsePassOne.Replace(expr,".$0.",-1,0); 515 expr = m_ParsePassOne.Replace(expr,".$1.",-1,0);
467
468 // add separators for array references
469 expr = m_ParsePassTwo.Replace(expr,".$0.",-1,0);
470 516
471 // add quotes to bare identifier 517 // add quotes to bare identifier
472 expr = m_ParsePassThree.Replace(expr,".{$1}",-1,0); 518 expr = m_ParsePassThree.Replace(expr,".{$1}",-1,0);
@@ -574,14 +620,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
574 // The path pointed to an intermediate hash structure 620 // The path pointed to an intermediate hash structure
575 if (result.Type == OSDType.Map) 621 if (result.Type == OSDType.Map)
576 { 622 {
577 value = OSDParser.SerializeJsonString(result as OSDMap); 623 value = OSDParser.SerializeJsonString(result as OSDMap,true);
578 return true; 624 return true;
579 } 625 }
580 626
581 // The path pointed to an intermediate hash structure 627 // The path pointed to an intermediate hash structure
582 if (result.Type == OSDType.Array) 628 if (result.Type == OSDType.Array)
583 { 629 {
584 value = OSDParser.SerializeJsonString(result as OSDArray); 630 value = OSDParser.SerializeJsonString(result as OSDArray,true);
585 return true; 631 return true;
586 } 632 }
587 633
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
index f1ce856..fb35068 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
@@ -227,7 +227,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
227 } 227 }
228 catch (Exception e) 228 catch (Exception e)
229 { 229 {
230 m_log.Error(string.Format("[JsonStore]: Unable to initialize store from {0}", value), e); 230 m_log.ErrorFormat("[JsonStore]: Unable to initialize store from {0}", value);
231 return false; 231 return false;
232 } 232 }
233 233
@@ -270,6 +270,38 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
270 /// 270 ///
271 /// </summary> 271 /// </summary>
272 // ----------------------------------------------------------------- 272 // -----------------------------------------------------------------
273 public JsonStoreNodeType GetPathType(UUID storeID, string path)
274 {
275 if (! m_enabled) return JsonStoreNodeType.Undefined;
276
277 JsonStore map = null;
278 lock (m_JsonValueStore)
279 {
280 if (! m_JsonValueStore.TryGetValue(storeID,out map))
281 {
282 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
283 return JsonStoreNodeType.Undefined;
284 }
285 }
286
287 try
288 {
289 lock (map)
290 return map.PathType(path);
291 }
292 catch (Exception e)
293 {
294 m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e);
295 }
296
297 return JsonStoreNodeType.Undefined;
298 }
299
300 // -----------------------------------------------------------------
301 /// <summary>
302 ///
303 /// </summary>
304 // -----------------------------------------------------------------
273 public bool TestPath(UUID storeID, string path, bool useJson) 305 public bool TestPath(UUID storeID, string path, bool useJson)
274 { 306 {
275 if (! m_enabled) return false; 307 if (! m_enabled) return false;
@@ -375,6 +407,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
375 /// 407 ///
376 /// </summary> 408 /// </summary>
377 // ----------------------------------------------------------------- 409 // -----------------------------------------------------------------
410 public int GetArrayLength(UUID storeID, string path)
411 {
412 if (! m_enabled) return -1;
413
414 JsonStore map = null;
415 lock (m_JsonValueStore)
416 {
417 if (! m_JsonValueStore.TryGetValue(storeID,out map))
418 return -1;
419 }
420
421 try
422 {
423 lock (map)
424 {
425 return map.ArrayLength(path);
426 }
427 }
428 catch (Exception e)
429 {
430 m_log.Error("[JsonStore]: unable to retrieve value", e);
431 }
432
433 return -1;
434 }
435
436 // -----------------------------------------------------------------
437 /// <summary>
438 ///
439 /// </summary>
440 // -----------------------------------------------------------------
378 public bool GetValue(UUID storeID, string path, bool useJson, out string value) 441 public bool GetValue(UUID storeID, string path, bool useJson, out string value)
379 { 442 {
380 value = String.Empty; 443 value = String.Empty;
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
index e436304..ef08c05 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
@@ -167,7 +167,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
167 try 167 try
168 { 168 {
169 m_comms.RegisterScriptInvocations(this); 169 m_comms.RegisterScriptInvocations(this);
170 170 m_comms.RegisterConstants(this);
171
171 // m_comms.RegisterScriptInvocation(this, "JsonCreateStore"); 172 // m_comms.RegisterScriptInvocation(this, "JsonCreateStore");
172 // m_comms.RegisterScriptInvocation(this, "JsonAttachObjectStore"); 173 // m_comms.RegisterScriptInvocation(this, "JsonAttachObjectStore");
173 // m_comms.RegisterScriptInvocation(this, "JsonDestroyStore"); 174 // m_comms.RegisterScriptInvocation(this, "JsonDestroyStore");
@@ -214,6 +215,22 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
214 215
215#endregion 216#endregion
216 217
218#region ScriptConstantsInterface
219
220 [ScriptConstant]
221 public static readonly int JSON_TYPE_UNDEF = (int)JsonStoreNodeType.Undefined;
222
223 [ScriptConstant]
224 public static readonly int JSON_TYPE_OBJECT = (int)JsonStoreNodeType.Object;
225
226 [ScriptConstant]
227 public static readonly int JSON_TYPE_ARRAY = (int)JsonStoreNodeType.Array;
228
229 [ScriptConstant]
230 public static readonly int JSON_TYPE_VALUE = (int)JsonStoreNodeType.Value;
231
232#endregion
233
217#region ScriptInvocationInteface 234#region ScriptInvocationInteface
218 // ----------------------------------------------------------------- 235 // -----------------------------------------------------------------
219 /// <summary> 236 /// <summary>
@@ -319,6 +336,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
319 /// </summary> 336 /// </summary>
320 // ----------------------------------------------------------------- 337 // -----------------------------------------------------------------
321 [ScriptInvocation] 338 [ScriptInvocation]
339 public int JsonGetPathType(UUID hostID, UUID scriptID, UUID storeID, string path)
340 {
341 return (int)m_store.GetPathType(storeID,path);
342 }
343
344 [ScriptInvocation]
322 public int JsonTestPath(UUID hostID, UUID scriptID, UUID storeID, string path) 345 public int JsonTestPath(UUID hostID, UUID scriptID, UUID storeID, string path)
323 { 346 {
324 return m_store.TestPath(storeID,path,false) ? 1 : 0; 347 return m_store.TestPath(storeID,path,false) ? 1 : 0;
@@ -342,7 +365,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
342 } 365 }
343 366
344 [ScriptInvocation] 367 [ScriptInvocation]
345 public int JsonSetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value) 368 public int JsonSetJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value)
346 { 369 {
347 return m_store.SetValue(storeID,path,value,true) ? 1 : 0; 370 return m_store.SetValue(storeID,path,value,true) ? 1 : 0;
348 } 371 }
@@ -364,6 +387,17 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
364 /// </summary> 387 /// </summary>
365 // ----------------------------------------------------------------- 388 // -----------------------------------------------------------------
366 [ScriptInvocation] 389 [ScriptInvocation]
390 public int JsonGetArrayLength(UUID hostID, UUID scriptID, UUID storeID, string path)
391 {
392 return m_store.GetArrayLength(storeID,path);
393 }
394
395 // -----------------------------------------------------------------
396 /// <summary>
397 ///
398 /// </summary>
399 // -----------------------------------------------------------------
400 [ScriptInvocation]
367 public string JsonGetValue(UUID hostID, UUID scriptID, UUID storeID, string path) 401 public string JsonGetValue(UUID hostID, UUID scriptID, UUID storeID, string path)
368 { 402 {
369 string value = String.Empty; 403 string value = String.Empty;
@@ -372,7 +406,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
372 } 406 }
373 407
374 [ScriptInvocation] 408 [ScriptInvocation]
375 public string JsonGetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) 409 public string JsonGetJson(UUID hostID, UUID scriptID, UUID storeID, string path)
376 { 410 {
377 string value = String.Empty; 411 string value = String.Empty;
378 m_store.GetValue(storeID,path,true, out value); 412 m_store.GetValue(storeID,path,true, out value);
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
index 717484c..3d9ad16 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
@@ -53,6 +53,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
53 private Scene m_scene; 53 private Scene m_scene;
54 private MockScriptEngine m_engine; 54 private MockScriptEngine m_engine;
55 private ScriptModuleCommsModule m_smcm; 55 private ScriptModuleCommsModule m_smcm;
56 private JsonStoreScriptModule m_jssm;
56 57
57 [TestFixtureSetUp] 58 [TestFixtureSetUp]
58 public void FixtureInit() 59 public void FixtureInit()
@@ -82,10 +83,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
82 m_engine = new MockScriptEngine(); 83 m_engine = new MockScriptEngine();
83 m_smcm = new ScriptModuleCommsModule(); 84 m_smcm = new ScriptModuleCommsModule();
84 JsonStoreModule jsm = new JsonStoreModule(); 85 JsonStoreModule jsm = new JsonStoreModule();
85 JsonStoreScriptModule jssm = new JsonStoreScriptModule(); 86 m_jssm = new JsonStoreScriptModule();
86 87
87 m_scene = new SceneHelpers().SetupScene(); 88 m_scene = new SceneHelpers().SetupScene();
88 SceneHelpers.SetupSceneModules(m_scene, configSource, m_engine, m_smcm, jsm, jssm); 89 SceneHelpers.SetupSceneModules(m_scene, configSource, m_engine, m_smcm, jsm, m_jssm);
89 90
90 try 91 try
91 { 92 {
@@ -115,8 +116,35 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
115 TestHelpers.InMethod(); 116 TestHelpers.InMethod();
116// TestHelpers.EnableLogging(); 117// TestHelpers.EnableLogging();
117 118
118 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); 119 // Test blank store
119 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); 120 {
121 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
122 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
123 }
124
125 // Test single element store
126 {
127 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
128 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
129 }
130
131 // Test with an integer value
132 {
133 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 42.15 }");
134 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
135
136 string value = (string)InvokeOp("JsonGetValue", storeId, "Hello");
137 Assert.That(value, Is.EqualTo("42.15"));
138 }
139
140 // Test with an array as the root node
141 {
142 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "[ 'one', 'two', 'three' ]");
143 Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
144
145 string value = (string)InvokeOp("JsonGetValue", storeId, "[1]");
146 Assert.That(value, Is.EqualTo("two"));
147 }
120 } 148 }
121 149
122 [Test] 150 [Test]
@@ -181,7 +209,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
181 } 209 }
182 210
183 [Test] 211 [Test]
184 public void TestJsonGetValueJson() 212 public void TestJsonGetJson()
185 { 213 {
186 TestHelpers.InMethod(); 214 TestHelpers.InMethod();
187// TestHelpers.EnableLogging(); 215// TestHelpers.EnableLogging();
@@ -189,26 +217,26 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
189 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }"); 217 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }");
190 218
191 { 219 {
192 string value = (string)InvokeOp("JsonGetValueJson", storeId, "Hello.World"); 220 string value = (string)InvokeOp("JsonGetJson", storeId, "Hello.World");
193 Assert.That(value, Is.EqualTo("'Two'")); 221 Assert.That(value, Is.EqualTo("'Two'"));
194 } 222 }
195 223
196 // Test get of path section instead of leaf 224 // Test get of path section instead of leaf
197 { 225 {
198 string value = (string)InvokeOp("JsonGetValueJson", storeId, "Hello"); 226 string value = (string)InvokeOp("JsonGetJson", storeId, "Hello");
199 Assert.That(value, Is.EqualTo("{\"World\":\"Two\"}")); 227 Assert.That(value, Is.EqualTo("{\"World\":\"Two\"}"));
200 } 228 }
201 229
202 // Test get of non-existing value 230 // Test get of non-existing value
203 { 231 {
204 string fakeValueGet = (string)InvokeOp("JsonGetValueJson", storeId, "foo"); 232 string fakeValueGet = (string)InvokeOp("JsonGetJson", storeId, "foo");
205 Assert.That(fakeValueGet, Is.EqualTo("")); 233 Assert.That(fakeValueGet, Is.EqualTo(""));
206 } 234 }
207 235
208 // Test get from non-existing store 236 // Test get from non-existing store
209 { 237 {
210 UUID fakeStoreId = TestHelpers.ParseTail(0x500); 238 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
211 string fakeStoreValueGet = (string)InvokeOp("JsonGetValueJson", fakeStoreId, "Hello"); 239 string fakeStoreValueGet = (string)InvokeOp("JsonGetJson", fakeStoreId, "Hello");
212 Assert.That(fakeStoreValueGet, Is.EqualTo("")); 240 Assert.That(fakeStoreValueGet, Is.EqualTo(""));
213 } 241 }
214 } 242 }
@@ -242,88 +270,236 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
242 TestHelpers.InMethod(); 270 TestHelpers.InMethod();
243// TestHelpers.EnableLogging(); 271// TestHelpers.EnableLogging();
244 272
245 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); 273 // Test remove of node in object pointing to a string
274 {
275 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
276
277 int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
278 Assert.That(returnValue, Is.EqualTo(1));
279
280 int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
281 Assert.That(result, Is.EqualTo(0));
282
283 string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello");
284 Assert.That(returnValue2, Is.EqualTo(""));
285 }
286
287 // Test remove of node in object pointing to another object
288 {
289 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Wally' } }");
290
291 int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
292 Assert.That(returnValue, Is.EqualTo(1));
293
294 int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
295 Assert.That(result, Is.EqualTo(0));
296
297 string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello");
298 Assert.That(returnValue2, Is.EqualTo(""));
299 }
300
301 // Test remove of node in an array
302 {
303 UUID storeId
304 = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : [ 'value1', 'value2' ] }");
305
306 int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]");
307 Assert.That(returnValue, Is.EqualTo(1));
246 308
247 int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello"); 309 int result = (int)InvokeOp("JsonTestPath", storeId, "Hello[0]");
248 Assert.That(returnValue, Is.EqualTo(1)); 310 Assert.That(result, Is.EqualTo(1));
311
312 result = (int)InvokeOp("JsonTestPath", storeId, "Hello[1]");
313 Assert.That(result, Is.EqualTo(0));
249 314
250 int result = (int)InvokeOp("JsonTestPath", storeId, "Hello"); 315 string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]");
251 Assert.That(result, Is.EqualTo(0)); 316 Assert.That(stringReturnValue, Is.EqualTo("value2"));
252 317
253 string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello"); 318 stringReturnValue = (string)InvokeOp("JsonGetJson", storeId, "Hello[1]");
254 Assert.That(returnValue2, Is.EqualTo("")); 319 Assert.That(stringReturnValue, Is.EqualTo(""));
320 }
255 321
256 // Test remove of non-existing value 322 // Test remove of non-existing value
257 int fakeValueRemove = (int)InvokeOp("JsonRemoveValue", storeId, "Hello"); 323 {
258 Assert.That(fakeValueRemove, Is.EqualTo(0)); 324 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
259 325
260 // Test get from non-existing store 326 int fakeValueRemove = (int)InvokeOp("JsonRemoveValue", storeId, "Cheese");
261 UUID fakeStoreId = TestHelpers.ParseTail(0x500); 327 Assert.That(fakeValueRemove, Is.EqualTo(0));
262 int fakeStoreValueRemove = (int)InvokeOp("JsonRemoveValue", fakeStoreId, "Hello"); 328 }
263 Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); 329
330 {
331 // Test get from non-existing store
332 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
333 int fakeStoreValueRemove = (int)InvokeOp("JsonRemoveValue", fakeStoreId, "Hello");
334 Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
335 }
264 } 336 }
265 337
338// [Test]
339// public void TestJsonTestPath()
340// {
341// TestHelpers.InMethod();
342//// TestHelpers.EnableLogging();
343//
344// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }");
345//
346// {
347// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello.World");
348// Assert.That(result, Is.EqualTo(1));
349// }
350//
351// // Test for path which does not resolve to a value.
352// {
353// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
354// Assert.That(result, Is.EqualTo(0));
355// }
356//
357// {
358// int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo");
359// Assert.That(result2, Is.EqualTo(0));
360// }
361//
362// // Test with fake store
363// {
364// UUID fakeStoreId = TestHelpers.ParseTail(0x500);
365// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello");
366// Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
367// }
368// }
369
370// [Test]
371// public void TestJsonTestPathJson()
372// {
373// TestHelpers.InMethod();
374//// TestHelpers.EnableLogging();
375//
376// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }");
377//
378// {
379// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello.World");
380// Assert.That(result, Is.EqualTo(1));
381// }
382//
383// // Test for path which does not resolve to a value.
384// {
385// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello");
386// Assert.That(result, Is.EqualTo(1));
387// }
388//
389// {
390// int result2 = (int)InvokeOp("JsonTestPathJson", storeId, "foo");
391// Assert.That(result2, Is.EqualTo(0));
392// }
393//
394// // Test with fake store
395// {
396// UUID fakeStoreId = TestHelpers.ParseTail(0x500);
397// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPathJson", fakeStoreId, "Hello");
398// Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
399// }
400// }
401
266 [Test] 402 [Test]
267 public void TestJsonTestPath() 403 public void TestGetArrayLength()
268 { 404 {
269 TestHelpers.InMethod(); 405 TestHelpers.InMethod();
270// TestHelpers.EnableLogging(); 406// TestHelpers.EnableLogging();
271 407
272 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }"); 408 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
273 409
274 { 410 {
275 int result = (int)InvokeOp("JsonTestPath", storeId, "Hello.World"); 411 int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello.World");
276 Assert.That(result, Is.EqualTo(1)); 412 Assert.That(result, Is.EqualTo(2));
277 } 413 }
278 414
279 // Test for path which does not resolve to a value. 415 // Test path which is not an array
280 { 416 {
281 int result = (int)InvokeOp("JsonTestPath", storeId, "Hello"); 417 int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello");
282 Assert.That(result, Is.EqualTo(0)); 418 Assert.That(result, Is.EqualTo(-1));
283 } 419 }
284 420
421 // Test fake path
285 { 422 {
286 int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo"); 423 int result = (int)InvokeOp("JsonGetArrayLength", storeId, "foo");
287 Assert.That(result2, Is.EqualTo(0)); 424 Assert.That(result, Is.EqualTo(-1));
288 } 425 }
289 426
290 // Test with fake store 427 // Test fake store
291 { 428 {
292 UUID fakeStoreId = TestHelpers.ParseTail(0x500); 429 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
293 int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello"); 430 int result = (int)InvokeOp("JsonGetArrayLength", fakeStoreId, "Hello.World");
294 Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); 431 Assert.That(result, Is.EqualTo(-1));
295 } 432 }
296 } 433 }
297 434
298 [Test] 435 [Test]
299 public void TestJsonTestPathJson() 436 public void TestJsonGetPathType()
300 { 437 {
301 TestHelpers.InMethod(); 438 TestHelpers.InMethod();
302// TestHelpers.EnableLogging(); 439// TestHelpers.EnableLogging();
303 440
304 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }"); 441 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
305 442
306 { 443 {
307 int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello.World"); 444 int result = (int)InvokeOp("JsonGetPathType", storeId, ".");
308 Assert.That(result, Is.EqualTo(1)); 445 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
309 } 446 }
310 447
311 // Test for path which does not resolve to a value.
312 { 448 {
313 int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello"); 449 int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
314 Assert.That(result, Is.EqualTo(1)); 450 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
315 } 451 }
316 452
317 { 453 {
318 int result2 = (int)InvokeOp("JsonTestPathJson", storeId, "foo"); 454 int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World");
319 Assert.That(result2, Is.EqualTo(0)); 455 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_ARRAY));
320 } 456 }
321 457
322 // Test with fake store 458 {
459 int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[0]");
460 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
461 }
462
463 {
464 int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[1]");
465 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
466 }
467
468 // Test for non-existant path
469 {
470 int result = (int)InvokeOp("JsonGetPathType", storeId, "foo");
471 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
472 }
473
474 // Test for non-existant store
323 { 475 {
324 UUID fakeStoreId = TestHelpers.ParseTail(0x500); 476 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
325 int fakeStoreValueRemove = (int)InvokeOp("JsonTestPathJson", fakeStoreId, "Hello"); 477 int result = (int)InvokeOp("JsonGetPathType", fakeStoreId, ".");
326 Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); 478 Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
479 }
480 }
481
482 [Test]
483 public void TestJsonList2Path()
484 {
485 TestHelpers.InMethod();
486// TestHelpers.EnableLogging();
487
488 // Invoking these methods directly since I just couldn't get comms module invocation to work for some reason
489 // - some confusion with the methods that take a params object[] invocation.
490 {
491 string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo" });
492 Assert.That(result, Is.EqualTo("{foo}"));
493 }
494
495 {
496 string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", "bar" });
497 Assert.That(result, Is.EqualTo("{foo}.{bar}"));
498 }
499
500 {
501 string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", 1, "bar" });
502 Assert.That(result, Is.EqualTo("{foo}.[1].{bar}"));
327 } 503 }
328 } 504 }
329 505
@@ -334,7 +510,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
334// TestHelpers.EnableLogging(); 510// TestHelpers.EnableLogging();
335 511
336 { 512 {
337 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); 513 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
338 514
339 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times"); 515 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times");
340 Assert.That(result, Is.EqualTo(1)); 516 Assert.That(result, Is.EqualTo(1));
@@ -343,9 +519,155 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
343 Assert.That(value, Is.EqualTo("Times")); 519 Assert.That(value, Is.EqualTo("Times"));
344 } 520 }
345 521
522 // Test setting a key containing periods with delineation
523 {
524 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
525
526 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun.Circus}", "Times");
527 Assert.That(result, Is.EqualTo(1));
528
529 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun.Circus}");
530 Assert.That(value, Is.EqualTo("Times"));
531 }
532
533 // *** Test [] ***
534
535 // Test setting a key containing unbalanced ] without delineation. Expecting failure
536 {
537 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
538
539 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun]Circus", "Times");
540 Assert.That(result, Is.EqualTo(0));
541
542 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun]Circus");
543 Assert.That(value, Is.EqualTo(""));
544 }
545
546 // Test setting a key containing unbalanced [ without delineation. Expecting failure
547 {
548 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
549
550 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[Circus", "Times");
551 Assert.That(result, Is.EqualTo(0));
552
553 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[Circus");
554 Assert.That(value, Is.EqualTo(""));
555 }
556
557 // Test setting a key containing unbalanced [] without delineation. Expecting failure
558 {
559 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
560
561 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[]Circus", "Times");
562 Assert.That(result, Is.EqualTo(0));
563
564 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[]Circus");
565 Assert.That(value, Is.EqualTo(""));
566 }
567
568 // Test setting a key containing unbalanced ] with delineation
569 {
570 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
571
572 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun]Circus}", "Times");
573 Assert.That(result, Is.EqualTo(1));
574
575 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun]Circus}");
576 Assert.That(value, Is.EqualTo("Times"));
577 }
578
579 // Test setting a key containing unbalanced [ with delineation
580 {
581 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
582
583 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[Circus}", "Times");
584 Assert.That(result, Is.EqualTo(1));
585
586 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[Circus}");
587 Assert.That(value, Is.EqualTo("Times"));
588 }
589
590 // Test setting a key containing empty balanced [] with delineation
591 {
592 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
593
594 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[]Circus}", "Times");
595 Assert.That(result, Is.EqualTo(1));
596
597 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[]Circus}");
598 Assert.That(value, Is.EqualTo("Times"));
599 }
600
601// // Commented out as this currently unexpectedly fails.
602// // Test setting a key containing brackets around an integer with delineation
603// {
604// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
605//
606// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[0]Circus}", "Times");
607// Assert.That(result, Is.EqualTo(1));
608//
609// string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[0]Circus}");
610// Assert.That(value, Is.EqualTo("Times"));
611// }
612
613 // *** Test {} ***
614
615 // Test setting a key containing unbalanced } without delineation. Expecting failure (?)
616 {
617 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
618
619 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun}Circus", "Times");
620 Assert.That(result, Is.EqualTo(0));
621
622 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus");
623 Assert.That(value, Is.EqualTo(""));
624 }
625
626 // Test setting a key containing unbalanced { without delineation. Expecting failure (?)
627 {
628 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
629
630 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun{Circus", "Times");
631 Assert.That(result, Is.EqualTo(0));
632
633 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus");
634 Assert.That(value, Is.EqualTo(""));
635 }
636
637// // Commented out as this currently unexpectedly fails.
638// // Test setting a key containing unbalanced }
639// {
640// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
641//
642// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun}Circus}", "Times");
643// Assert.That(result, Is.EqualTo(0));
644// }
645
646 // Test setting a key containing unbalanced { with delineation
647 {
648 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
649
650 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Circus}", "Times");
651 Assert.That(result, Is.EqualTo(1));
652
653 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Circus}");
654 Assert.That(value, Is.EqualTo("Times"));
655 }
656
657 // Test setting a key containing balanced {} with delineation. This should fail.
658 {
659 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
660
661 int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Filled}Circus}", "Times");
662 Assert.That(result, Is.EqualTo(0));
663
664 string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Filled}Circus}");
665 Assert.That(value, Is.EqualTo(""));
666 }
667
346 // Test setting to location that does not exist. This should fail. 668 // Test setting to location that does not exist. This should fail.
347 { 669 {
348 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); 670 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
349 671
350 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun.Circus", "Times"); 672 int result = (int)InvokeOp("JsonSetValue", storeId, "Fun.Circus", "Times");
351 Assert.That(result, Is.EqualTo(0)); 673 Assert.That(result, Is.EqualTo(0));
@@ -363,27 +685,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
363 } 685 }
364 686
365 [Test] 687 [Test]
366 public void TestJsonSetValueJson() 688 public void TestJsonSetJson()
367 { 689 {
368 TestHelpers.InMethod(); 690 TestHelpers.InMethod();
369// TestHelpers.EnableLogging(); 691// TestHelpers.EnableLogging();
370 692
371 // Single quoted token case 693 // Single quoted token case
372// { 694 {
373// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); 695 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
374// 696
375// int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun", "'Times'"); 697 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "'Times'");
376// Assert.That(result, Is.EqualTo(1)); 698 Assert.That(result, Is.EqualTo(1));
377// 699
378// string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); 700 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
379// Assert.That(value, Is.EqualTo("Times")); 701 Assert.That(value, Is.EqualTo("Times"));
380// } 702 }
381 703
382 // Sub-tree case 704 // Sub-tree case
383 { 705 {
384 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); 706 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
385 707
386 int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun", "{ 'Filled' : 'Times' }"); 708 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "{ 'Filled' : 'Times' }");
387 Assert.That(result, Is.EqualTo(1)); 709 Assert.That(result, Is.EqualTo(1));
388 710
389 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Filled"); 711 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Filled");
@@ -394,7 +716,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
394 { 716 {
395 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); 717 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
396 718
397 int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun", "Times"); 719 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "Times");
398 Assert.That(result, Is.EqualTo(0)); 720 Assert.That(result, Is.EqualTo(0));
399 721
400 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); 722 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
@@ -405,7 +727,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
405 { 727 {
406 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); 728 UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
407 729
408 int result = (int)InvokeOp("JsonSetValueJson", storeId, "Fun.Circus", "'Times'"); 730 int result = (int)InvokeOp("JsonSetJson", storeId, "Fun.Circus", "'Times'");
409 Assert.That(result, Is.EqualTo(0)); 731 Assert.That(result, Is.EqualTo(0));
410 732
411 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus"); 733 string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus");
@@ -415,7 +737,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
415 // Test with fake store 737 // Test with fake store
416 { 738 {
417 UUID fakeStoreId = TestHelpers.ParseTail(0x500); 739 UUID fakeStoreId = TestHelpers.ParseTail(0x500);
418 int fakeStoreValueSet = (int)InvokeOp("JsonSetValueJson", fakeStoreId, "Hello", "'World'"); 740 int fakeStoreValueSet = (int)InvokeOp("JsonSetJson", fakeStoreId, "Hello", "'World'");
419 Assert.That(fakeStoreValueSet, Is.EqualTo(0)); 741 Assert.That(fakeStoreValueSet, Is.EqualTo(0));
420 } 742 }
421 } 743 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
index 7ab86d2..3f83ef0 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
@@ -225,9 +225,10 @@ public enum CollisionFlags : uint
225 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, 225 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
226 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 226 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
227 // Following used by BulletSim to control collisions and updates 227 // Following used by BulletSim to control collisions and updates
228 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 228 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed
229 BS_FLOATS_ON_WATER = 1 << 11, 229 BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level
230 BS_VEHICLE_COLLISIONS = 1 << 12, 230 BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking
231 BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape
231 BS_NONE = 0, 232 BS_NONE = 0,
232 BS_ALL = 0xFFFFFFFF 233 BS_ALL = 0xFFFFFFFF
233}; 234};
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index f781aea..8dca7c6 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -83,7 +83,7 @@ public sealed class BSCharacter : BSPhysObject
83 _velocity = OMV.Vector3.Zero; 83 _velocity = OMV.Vector3.Zero;
84 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 84 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
85 Friction = BSParam.AvatarStandingFriction; 85 Friction = BSParam.AvatarStandingFriction;
86 Density = BSParam.AvatarDensity; 86 Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor;
87 87
88 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 88 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
89 // replace with the default values. 89 // replace with the default values.
@@ -231,6 +231,15 @@ public sealed class BSCharacter : BSPhysObject
231 PhysicsScene.PE.SetFriction(PhysBody, Friction); 231 PhysicsScene.PE.SetFriction(PhysBody, Friction);
232 } 232 }
233 } 233 }
234 else
235 {
236 if (Flying)
237 {
238 // Flying and not collising and velocity nearly zero.
239 ZeroMotion(true /* inTaintTime */);
240 }
241 }
242
234 DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding); 243 DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding);
235 } 244 }
236 else 245 else
@@ -274,7 +283,7 @@ public sealed class BSCharacter : BSPhysObject
274 // This test is done if moving forward, not flying and is colliding with something. 283 // This test is done if moving forward, not flying and is colliding with something.
275 // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}", 284 // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
276 // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count); 285 // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
277 if (IsColliding && !Flying && TargetSpeed > 0.1f /* && ForwardSpeed < 0.1f */) 286 if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
278 { 287 {
279 // The range near the character's feet where we will consider stairs 288 // The range near the character's feet where we will consider stairs
280 float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f; 289 float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
@@ -869,7 +878,7 @@ public sealed class BSCharacter : BSPhysObject
869 * Math.Min(Size.X, Size.Y) / 2 878 * Math.Min(Size.X, Size.Y) / 2
870 * Size.Y / 2f // plus the volume of the capsule end caps 879 * Size.Y / 2f // plus the volume of the capsule end caps
871 ); 880 );
872 _mass = Density * _avatarVolume; 881 _mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
873 } 882 }
874 883
875 // The physics engine says that properties have updated. Update same and inform 884 // The physics engine says that properties have updated. Update same and inform
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index e35311f..4ece1eb 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -127,6 +127,8 @@ public abstract class BSLinkset
127 m_children = new HashSet<BSPrimLinkable>(); 127 m_children = new HashSet<BSPrimLinkable>();
128 LinksetMass = parent.RawMass; 128 LinksetMass = parent.RawMass;
129 Rebuilding = false; 129 Rebuilding = false;
130
131 parent.ClearDisplacement();
130 } 132 }
131 133
132 // Link to a linkset where the child knows the parent. 134 // Link to a linkset where the child knows the parent.
@@ -280,6 +282,7 @@ public abstract class BSLinkset
280 return mass; 282 return mass;
281 } 283 }
282 284
285 // Computes linkset's center of mass in world coordinates.
283 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() 286 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
284 { 287 {
285 OMV.Vector3 com; 288 OMV.Vector3 com;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index 36bae9b..4ce58c7 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -93,7 +93,8 @@ public sealed class BSLinksetCompound : BSLinkset
93{ 93{
94 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; 94 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
95 95
96 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) : base(scene, parent) 96 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
97 : base(scene, parent)
97 { 98 {
98 } 99 }
99 100
@@ -217,59 +218,45 @@ public sealed class BSLinksetCompound : BSLinkset
217 // and that is caused by us updating the object. 218 // and that is caused by us updating the object.
218 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) 219 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
219 { 220 {
220 // Gather the child info. It might not be there if the linkset is in transition.
221 BSLinksetCompoundInfo lsi = updated.LinksetInfo as BSLinksetCompoundInfo;
222 if (lsi != null)
223 {
224 // Since the child moved or rotationed, it needs a new relative position within the linkset
225 BSLinksetCompoundInfo newLsi = new BSLinksetCompoundInfo(lsi.Index, LinksetRoot, updated, OMV.Vector3.Zero);
226 updated.LinksetInfo = newLsi;
227
228 // Find the physical instance of the child 221 // Find the physical instance of the child
229 if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) 222 if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape))
223 {
224 // It is possible that the linkset is still under construction and the child is not yet
225 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
226 // build the whole thing with the new position or rotation.
227 // The index must be checked because Bullet references the child array but does no validity
228 // checking of the child index passed.
229 int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape);
230 if (updated.LinksetChildIndex < numLinksetChildren)
230 { 231 {
231 // It is possible that the linkset is still under construction and the child is not yet 232 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex);
232 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will 233 if (linksetChildShape.HasPhysicalShape)
233 // build the whole thing with the new position or rotation.
234 // The index must be checked because Bullet references the child array but does no validity
235 // checking of the child index passed.
236 int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape);
237 if (lsi.Index < numLinksetChildren)
238 { 234 {
239 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, lsi.Index); 235 // Found the child shape within the compound shape
240 if (linksetChildShape.HasPhysicalShape) 236 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex,
241 { 237 updated.RawPosition - LinksetRoot.RawPosition,
242 // Found the child shape within the compound shape 238 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
243 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, lsi.Index, 239 true /* shouldRecalculateLocalAabb */);
244 newLsi.OffsetFromCenterOfMass, 240 updatedChild = true;
245 newLsi.OffsetRot, 241 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
246 true /* shouldRecalculateLocalAabb */); 242 updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
247 updatedChild = true;
248 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},newLsi={2}",
249 updated.LocalID, whichUpdated, newLsi);
250 }
251 else // DEBUG DEBUG
252 { // DEBUG DEBUG
253 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
254 updated.LocalID, linksetChildShape);
255 } // DEBUG DEBUG
256 } 243 }
257 else // DEBUG DEBUG 244 else // DEBUG DEBUG
258 { // DEBUG DEBUG 245 { // DEBUG DEBUG
259 // the child is not yet in the compound shape. This is non-fatal. 246 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
260 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}", 247 updated.LocalID, linksetChildShape);
261 updated.LocalID, numLinksetChildren, lsi.Index);
262 } // DEBUG DEBUG 248 } // DEBUG DEBUG
263 } 249 }
264 else // DEBUG DEBUG 250 else // DEBUG DEBUG
265 { // DEBUG DEBUG 251 { // DEBUG DEBUG
266 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID); 252 // the child is not yet in the compound shape. This is non-fatal.
253 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
254 updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
267 } // DEBUG DEBUG 255 } // DEBUG DEBUG
268 } 256 }
269 else // DEBUG DEBUG 257 else // DEBUG DEBUG
270 { // DEBUG DEBUG 258 { // DEBUG DEBUG
271 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noLinkSetInfo,rootPhysShape={1}", 259 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
272 updated.LocalID, LinksetRoot.PhysShape);
273 } // DEBUG DEBUG 260 } // DEBUG DEBUG
274 261
275 if (!updatedChild) 262 if (!updatedChild)
@@ -379,6 +366,8 @@ public sealed class BSLinksetCompound : BSLinkset
379 // Safe to call even if the child is not really in the linkset. 366 // Safe to call even if the child is not really in the linkset.
380 protected override void RemoveChildFromLinkset(BSPrimLinkable child) 367 protected override void RemoveChildFromLinkset(BSPrimLinkable child)
381 { 368 {
369 child.ClearDisplacement();
370
382 if (m_children.Remove(child)) 371 if (m_children.Remove(child))
383 { 372 {
384 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 373 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
@@ -424,30 +413,31 @@ public sealed class BSLinksetCompound : BSLinkset
424 // The center of mass for the linkset is the geometric center of the group. 413 // The center of mass for the linkset is the geometric center of the group.
425 // Compute a displacement for each component so it is relative to the center-of-mass. 414 // Compute a displacement for each component so it is relative to the center-of-mass.
426 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass 415 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
427 OMV.Vector3 centerOfMass; 416 OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition;
428 OMV.Vector3 centerDisplacement = OMV.Vector3.Zero; 417 if (!disableCOM) // DEBUG DEBUG
429 if (disableCOM) // DEBUG DEBUG
430 { // DEBUG DEBUG
431 centerOfMass = LinksetRoot.RawPosition; // DEBUG DEBUG
432 // LinksetRoot.PositionDisplacement = OMV.Vector3.Zero;
433 } // DEBUG DEBUG
434 else
435 { 418 {
436 centerOfMass = ComputeLinksetCenterOfMass(); 419 // Compute a center-of-mass in world coordinates.
437 // 'centerDisplacement' is the value to *add* to all the shape offsets 420 centerOfMassW = ComputeLinksetCenterOfMass();
438 centerDisplacement = LinksetRoot.RawPosition - centerOfMass;
439
440 // Since we're displacing the center of the shape, we need to move the body in the world
441 // LinksetRoot.PositionDisplacement = centerDisplacement;
442
443 // This causes the root prim position to be set properly based on the new PositionDisplacement
444 LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
445 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
446 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0, -centerDisplacement, OMV.Quaternion.Identity, false);
447 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
448 LinksetRoot.LocalID, centerOfMass, LinksetRoot.RawPosition, centerDisplacement);
449 } 421 }
450 422
423 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
424
425 // 'centerDisplacement' is the value to subtract from children to give physical offset position
426 OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
427 LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement);
428
429 // This causes the physical position of the root prim to be offset to accomodate for the displacements
430 LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
431
432 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
433 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */,
434 -centerDisplacement,
435 OMV.Quaternion.Identity, // LinksetRoot.RawOrientation,
436 false /* shouldRecalculateLocalAabb (is done later after linkset built) */);
437
438 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
439 LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement);
440
451 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", 441 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
452 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); 442 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
453 443
@@ -455,38 +445,33 @@ public sealed class BSLinksetCompound : BSLinkset
455 int memberIndex = 1; 445 int memberIndex = 1;
456 ForEachMember(delegate(BSPrimLinkable cPrim) 446 ForEachMember(delegate(BSPrimLinkable cPrim)
457 { 447 {
458 if (!IsRoot(cPrim)) 448 if (IsRoot(cPrim))
459 { 449 {
460 // Compute the displacement of the child from the root of the linkset. 450 cPrim.LinksetChildIndex = 0;
461 // This info is saved in the child prim so the relationship does not 451 }
462 // change over time and the new child position can be computed 452 else
463 // when the linkset is being disassembled (the linkset may have moved). 453 {
464 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; 454 cPrim.LinksetChildIndex = memberIndex;
465 if (lci == null)
466 {
467 lci = new BSLinksetCompoundInfo(memberIndex, LinksetRoot, cPrim, centerDisplacement);
468 cPrim.LinksetInfo = lci;
469 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
470 }
471
472 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},lci={3}",
473 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci);
474 455
475 if (cPrim.PhysShape.isNativeShape) 456 if (cPrim.PhysShape.isNativeShape)
476 { 457 {
477 // A native shape is turned into a hull collision shape because native 458 // A native shape is turned into a hull collision shape because native
478 // shapes are not shared so we have to hullify it so it will be tracked 459 // shapes are not shared so we have to hullify it so it will be tracked
479 // and freed at the correct time. This also solves the scaling problem 460 // and freed at the correct time. This also solves the scaling problem
480 // (native shapes scaled but hull/meshes are assumed to not be). 461 // (native shapes scale but hull/meshes are assumed to not be).
481 // TODO: decide of the native shape can just be used in the compound shape. 462 // TODO: decide of the native shape can just be used in the compound shape.
482 // Use call to CreateGeomNonSpecial(). 463 // Use call to CreateGeomNonSpecial().
483 BulletShape saveShape = cPrim.PhysShape; 464 BulletShape saveShape = cPrim.PhysShape;
484 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape 465 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
485 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
486 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); 466 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
487 BulletShape newShape = cPrim.PhysShape; 467 BulletShape newShape = cPrim.PhysShape;
488 cPrim.PhysShape = saveShape; 468 cPrim.PhysShape = saveShape;
489 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetFromCenterOfMass, lci.OffsetRot); 469
470 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
471 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
472 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
473 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
474 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
490 } 475 }
491 else 476 else
492 { 477 {
@@ -498,9 +483,13 @@ public sealed class BSLinksetCompound : BSLinkset
498 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 483 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
499 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 484 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
500 } 485 }
501 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetFromCenterOfMass, lci.OffsetRot); 486 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
487 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
488 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
489 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
490 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
491
502 } 492 }
503 lci.Index = memberIndex;
504 memberIndex++; 493 memberIndex++;
505 } 494 }
506 return false; // 'false' says to move onto the next child in the list 495 return false; // 'false' says to move onto the next child in the list
@@ -509,12 +498,16 @@ public sealed class BSLinksetCompound : BSLinkset
509 // With all of the linkset packed into the root prim, it has the mass of everyone. 498 // With all of the linkset packed into the root prim, it has the mass of everyone.
510 LinksetMass = ComputeLinksetMass(); 499 LinksetMass = ComputeLinksetMass();
511 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); 500 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
501
502 // Enable the physical position updator to return the position and rotation of the root shape
503 PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
512 } 504 }
513 finally 505 finally
514 { 506 {
515 Rebuilding = false; 507 Rebuilding = false;
516 } 508 }
517 509
510 // See that the Aabb surrounds the new shape
518 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); 511 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
519 } 512 }
520} 513}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index 3e0b4bc..329169f 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -49,6 +49,7 @@ public static class BSParam
49 public static float MaxLinearVelocity { get; private set; } 49 public static float MaxLinearVelocity { get; private set; }
50 public static float MaxAngularVelocity { get; private set; } 50 public static float MaxAngularVelocity { get; private set; }
51 public static float MaxAddForceMagnitude { get; private set; } 51 public static float MaxAddForceMagnitude { get; private set; }
52 public static float DensityScaleFactor { get; private set; }
52 53
53 public static float LinearDamping { get; private set; } 54 public static float LinearDamping { get; private set; }
54 public static float AngularDamping { get; private set; } 55 public static float AngularDamping { get; private set; }
@@ -281,29 +282,35 @@ public static class BSParam
281 new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", 282 new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
282 0.0001f, 283 0.0001f,
283 (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); }, 284 (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
284 (s) => { return (float)MinimumObjectMass; }, 285 (s) => { return MinimumObjectMass; },
285 (s,p,l,v) => { MinimumObjectMass = v; } ), 286 (s,p,l,v) => { MinimumObjectMass = v; } ),
286 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 287 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
287 10000.01f, 288 10000.01f,
288 (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); }, 289 (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
289 (s) => { return (float)MaximumObjectMass; }, 290 (s) => { return MaximumObjectMass; },
290 (s,p,l,v) => { MaximumObjectMass = v; } ), 291 (s,p,l,v) => { MaximumObjectMass = v; } ),
291 new ParameterDefn("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object", 292 new ParameterDefn("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object",
292 1000.0f, 293 1000.0f,
293 (s,cf,p,v) => { MaxLinearVelocity = cf.GetFloat(p, v); }, 294 (s,cf,p,v) => { MaxLinearVelocity = cf.GetFloat(p, v); },
294 (s) => { return (float)MaxLinearVelocity; }, 295 (s) => { return MaxLinearVelocity; },
295 (s,p,l,v) => { MaxLinearVelocity = v; } ), 296 (s,p,l,v) => { MaxLinearVelocity = v; } ),
296 new ParameterDefn("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object", 297 new ParameterDefn("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object",
297 1000.0f, 298 1000.0f,
298 (s,cf,p,v) => { MaxAngularVelocity = cf.GetFloat(p, v); }, 299 (s,cf,p,v) => { MaxAngularVelocity = cf.GetFloat(p, v); },
299 (s) => { return (float)MaxAngularVelocity; }, 300 (s) => { return MaxAngularVelocity; },
300 (s,p,l,v) => { MaxAngularVelocity = v; } ), 301 (s,p,l,v) => { MaxAngularVelocity = v; } ),
301 // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject 302 // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject
302 new ParameterDefn("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)", 303 new ParameterDefn("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)",
303 20000.0f, 304 20000.0f,
304 (s,cf,p,v) => { MaxAddForceMagnitude = cf.GetFloat(p, v); }, 305 (s,cf,p,v) => { MaxAddForceMagnitude = cf.GetFloat(p, v); },
305 (s) => { return (float)MaxAddForceMagnitude; }, 306 (s) => { return MaxAddForceMagnitude; },
306 (s,p,l,v) => { MaxAddForceMagnitude = v; } ), 307 (s,p,l,v) => { MaxAddForceMagnitude = v; } ),
308 // Density is passed around as 100kg/m3. This scales that to 1kg/m3.
309 new ParameterDefn("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
310 0.01f,
311 (s,cf,p,v) => { DensityScaleFactor = cf.GetFloat(p, v); },
312 (s) => { return DensityScaleFactor; },
313 (s,p,l,v) => { DensityScaleFactor = v; } ),
307 314
308 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 315 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
309 2200f, 316 2200f,
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index de69fa0..f953c1e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -99,6 +99,9 @@ public abstract class BSPhysObject : PhysicsActor
99 CollisionAccumulation = 0; 99 CollisionAccumulation = 0;
100 ColliderIsMoving = false; 100 ColliderIsMoving = false;
101 CollisionScore = 0; 101 CollisionScore = 0;
102
103 // All axis free.
104 LockedAxis = LockedAxisFree;
102 } 105 }
103 106
104 // Tell the object to clean up. 107 // Tell the object to clean up.
@@ -136,6 +139,7 @@ public abstract class BSPhysObject : PhysicsActor
136 139
137 // The objects base shape information. Null if not a prim type shape. 140 // The objects base shape information. Null if not a prim type shape.
138 public PrimitiveBaseShape BaseShape { get; protected set; } 141 public PrimitiveBaseShape BaseShape { get; protected set; }
142
139 // Some types of objects have preferred physical representations. 143 // Some types of objects have preferred physical representations.
140 // Returns SHAPE_UNKNOWN if there is no preference. 144 // Returns SHAPE_UNKNOWN if there is no preference.
141 public virtual BSPhysicsShapeType PreferredPhysicalShape 145 public virtual BSPhysicsShapeType PreferredPhysicalShape
@@ -150,15 +154,17 @@ public abstract class BSPhysObject : PhysicsActor
150 public EntityProperties LastEntityProperties { get; set; } 154 public EntityProperties LastEntityProperties { get; set; }
151 155
152 public virtual OMV.Vector3 Scale { get; set; } 156 public virtual OMV.Vector3 Scale { get; set; }
153 public abstract bool IsSolid { get; }
154 public abstract bool IsStatic { get; }
155 public abstract bool IsSelected { get; }
156 157
157 // It can be confusing for an actor to know if it should move or update an object 158 // It can be confusing for an actor to know if it should move or update an object
158 // depeneding on the setting of 'selected', 'physical, ... 159 // depeneding on the setting of 'selected', 'physical, ...
159 // This flag is the true test -- if true, the object is being acted on in the physical world 160 // This flag is the true test -- if true, the object is being acted on in the physical world
160 public abstract bool IsPhysicallyActive { get; } 161 public abstract bool IsPhysicallyActive { get; }
161 162
163 // Detailed state of the object.
164 public abstract bool IsSolid { get; }
165 public abstract bool IsStatic { get; }
166 public abstract bool IsSelected { get; }
167
162 // Materialness 168 // Materialness
163 public MaterialAttributes.Material Material { get; private set; } 169 public MaterialAttributes.Material Material { get; private set; }
164 public override void SetMaterial(int material) 170 public override void SetMaterial(int material)
@@ -169,7 +175,8 @@ public abstract class BSPhysObject : PhysicsActor
169 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); 175 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
170 Friction = matAttrib.friction; 176 Friction = matAttrib.friction;
171 Restitution = matAttrib.restitution; 177 Restitution = matAttrib.restitution;
172 Density = matAttrib.density; 178 Density = matAttrib.density / BSParam.DensityScaleFactor;
179 DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
173 } 180 }
174 181
175 // Stop all physical motion. 182 // Stop all physical motion.
@@ -185,14 +192,6 @@ public abstract class BSPhysObject : PhysicsActor
185 public abstract OMV.Quaternion RawOrientation { get; set; } 192 public abstract OMV.Quaternion RawOrientation { get; set; }
186 public abstract OMV.Quaternion ForceOrientation { get; set; } 193 public abstract OMV.Quaternion ForceOrientation { get; set; }
187 194
188 public virtual float TargetSpeed
189 {
190 get
191 {
192 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
193 return characterOrientedVelocity.X;
194 }
195 }
196 public abstract OMV.Vector3 RawVelocity { get; set; } 195 public abstract OMV.Vector3 RawVelocity { get; set; }
197 public abstract OMV.Vector3 ForceVelocity { get; set; } 196 public abstract OMV.Vector3 ForceVelocity { get; set; }
198 197
@@ -202,6 +201,7 @@ public abstract class BSPhysObject : PhysicsActor
202 201
203 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } 202 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
204 203
204 // The current velocity forward
205 public virtual float ForwardSpeed 205 public virtual float ForwardSpeed
206 { 206 {
207 get 207 get
@@ -210,6 +210,22 @@ public abstract class BSPhysObject : PhysicsActor
210 return characterOrientedVelocity.X; 210 return characterOrientedVelocity.X;
211 } 211 }
212 } 212 }
213 // The forward speed we are trying to achieve (TargetVelocity)
214 public virtual float TargetVelocitySpeed
215 {
216 get
217 {
218 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
219 return characterOrientedVelocity.X;
220 }
221 }
222
223 // The user can optionally set the center of mass. The user's setting will override any
224 // computed center-of-mass (like in linksets).
225 public OMV.Vector3? UserSetCenterOfMass { get; set; }
226
227 public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free.
228 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free
213 229
214 #region Collisions 230 #region Collisions
215 231
@@ -407,9 +423,7 @@ public abstract class BSPhysObject : PhysicsActor
407 { 423 {
408 // Clean out any existing action 424 // Clean out any existing action
409 UnRegisterPreStepAction(op, id); 425 UnRegisterPreStepAction(op, id);
410
411 RegisteredPrestepActions[identifier] = actn; 426 RegisteredPrestepActions[identifier] = actn;
412
413 PhysicsScene.BeforeStep += actn; 427 PhysicsScene.BeforeStep += actn;
414 } 428 }
415 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); 429 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
@@ -455,9 +469,7 @@ public abstract class BSPhysObject : PhysicsActor
455 { 469 {
456 // Clean out any existing action 470 // Clean out any existing action
457 UnRegisterPostStepAction(op, id); 471 UnRegisterPostStepAction(op, id);
458
459 RegisteredPoststepActions[identifier] = actn; 472 RegisteredPoststepActions[identifier] = actn;
460
461 PhysicsScene.AfterStep += actn; 473 PhysicsScene.AfterStep += actn;
462 } 474 }
463 DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier); 475 DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
@@ -494,7 +506,58 @@ public abstract class BSPhysObject : PhysicsActor
494 } 506 }
495 DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID); 507 DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
496 } 508 }
497 509
510 // When an update to the physical properties happens, this event is fired to let
511 // different actors to modify the update before it is passed around
512 public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
513 public event PreUpdatePropertyAction OnPreUpdateProperty;
514 protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
515 {
516 PreUpdatePropertyAction actions = OnPreUpdateProperty;
517 if (actions != null)
518 actions(ref entprop);
519 }
520
521 private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>();
522 public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn)
523 {
524 lock (RegisteredPreUpdatePropertyActions)
525 {
526 // Clean out any existing action
527 UnRegisterPreUpdatePropertyAction(identifier);
528 RegisteredPreUpdatePropertyActions[identifier] = actn;
529 OnPreUpdateProperty += actn;
530 }
531 DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier);
532 }
533 public bool UnRegisterPreUpdatePropertyAction(string identifier)
534 {
535 bool removed = false;
536 lock (RegisteredPreUpdatePropertyActions)
537 {
538 if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier))
539 {
540 OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier];
541 RegisteredPreUpdatePropertyActions.Remove(identifier);
542 removed = true;
543 }
544 }
545 DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed);
546 return removed;
547 }
548 public void UnRegisterAllPreUpdatePropertyActions()
549 {
550 lock (RegisteredPreUpdatePropertyActions)
551 {
552 foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions)
553 {
554 OnPreUpdateProperty -= kvp.Value;
555 }
556 RegisteredPreUpdatePropertyActions.Clear();
557 }
558 DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID);
559 }
560
498 #endregion // Per Simulation Step actions 561 #endregion // Per Simulation Step actions
499 562
500 // High performance detailed logging routine used by the physical objects. 563 // High performance detailed logging routine used by the physical objects.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index cf7aa0f..0323b0d 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -242,6 +242,45 @@ public class BSPrim : BSPhysObject
242 public override void LockAngularMotion(OMV.Vector3 axis) 242 public override void LockAngularMotion(OMV.Vector3 axis)
243 { 243 {
244 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 244 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
245
246 OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f);
247 if (axis.X != 1) locking.X = 0f;
248 if (axis.Y != 1) locking.Y = 0f;
249 if (axis.Z != 1) locking.Z = 0f;
250 LockedAxis = locking;
251
252 /* Not implemented yet
253 if (LockedAxis != LockedAxisFree)
254 {
255 // Something is locked so start the thingy that keeps that axis from changing
256 RegisterPreUpdatePropertyAction("BSPrim.LockAngularMotion", delegate(ref EntityProperties entprop)
257 {
258 if (LockedAxis != LockedAxisFree)
259 {
260 if (IsPhysicallyActive)
261 {
262 // Bullet can lock axis but it only works for global axis.
263 // Check if this prim is aligned on global axis and use Bullet's
264 // system if so.
265
266 ForceOrientation = entprop.Rotation;
267 ForceRotationalVelocity = entprop.RotationalVelocity;
268 }
269 }
270 else
271 {
272 UnRegisterPreUpdatePropertyAction("BSPrim.LockAngularMotion");
273 }
274
275 });
276 }
277 else
278 {
279 // Everything seems unlocked
280 UnRegisterPreUpdatePropertyAction("BSPrim.LockAngularMotion");
281 }
282 */
283
245 return; 284 return;
246 } 285 }
247 286
@@ -311,7 +350,8 @@ public class BSPrim : BSPhysObject
311 350
312 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); 351 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
313 OMV.Vector3 upForce = OMV.Vector3.Zero; 352 OMV.Vector3 upForce = OMV.Vector3.Zero;
314 if (RawPosition.Z < terrainHeight) 353 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
354 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
315 { 355 {
316 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); 356 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
317 float targetHeight = terrainHeight + (Size.Z / 2f); 357 float targetHeight = terrainHeight + (Size.Z / 2f);
@@ -442,7 +482,7 @@ public class BSPrim : BSPhysObject
442 RegisterPreStepAction("BSPrim.setForce", LocalID, 482 RegisterPreStepAction("BSPrim.setForce", LocalID,
443 delegate(float timeStep) 483 delegate(float timeStep)
444 { 484 {
445 if (!IsPhysicallyActive) 485 if (!IsPhysicallyActive || _force == OMV.Vector3.Zero)
446 { 486 {
447 UnRegisterPreStepAction("BSPrim.setForce", LocalID); 487 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
448 return; 488 return;
@@ -576,6 +616,8 @@ public class BSPrim : BSPhysObject
576 } 616 }
577 } 617 }
578 } 618 }
619 // The simulator/viewer keep density as 100kg/m3.
620 // Remember to use BSParam.DensityScaleFactor to create the physical density.
579 public override float Density 621 public override float Density
580 { 622 {
581 get { return base.Density; } 623 get { return base.Density; }
@@ -647,7 +689,7 @@ public class BSPrim : BSPhysObject
647 RegisterPreStepAction("BSPrim.setTorque", LocalID, 689 RegisterPreStepAction("BSPrim.setTorque", LocalID,
648 delegate(float timeStep) 690 delegate(float timeStep)
649 { 691 {
650 if (!IsPhysicallyActive) 692 if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero)
651 { 693 {
652 UnRegisterPreStepAction("BSPrim.setTorque", LocalID); 694 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
653 return; 695 return;
@@ -1569,7 +1611,8 @@ public class BSPrim : BSPhysObject
1569 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; 1611 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1570 volume *= (profileEnd - profileBegin); 1612 volume *= (profileEnd - profileBegin);
1571 1613
1572 returnMass = Density * volume; 1614 returnMass = Density * BSParam.DensityScaleFactor * volume;
1615 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1573 1616
1574 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); 1617 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1575 1618
@@ -1607,6 +1650,8 @@ public class BSPrim : BSPhysObject
1607 // the world that things have changed. 1650 // the world that things have changed.
1608 public override void UpdateProperties(EntityProperties entprop) 1651 public override void UpdateProperties(EntityProperties entprop)
1609 { 1652 {
1653 TriggerPreUpdatePropertyAction(ref entprop);
1654
1610 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet 1655 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1611 // TODO: handle physics introduced by Bullet with computed vehicle physics. 1656 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1612 if (VehicleController.IsActive) 1657 if (VehicleController.IsActive)
@@ -1619,7 +1664,11 @@ public class BSPrim : BSPhysObject
1619 // Assign directly to the local variables so the normal set actions do not happen 1664 // Assign directly to the local variables so the normal set actions do not happen
1620 _position = entprop.Position; 1665 _position = entprop.Position;
1621 _orientation = entprop.Rotation; 1666 _orientation = entprop.Rotation;
1622 _velocity = entprop.Velocity; 1667 // _velocity = entprop.Velocity;
1668 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1669 // very sensitive to velocity changes.
1670 if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f))
1671 _velocity = entprop.Velocity;
1623 _acceleration = entprop.Acceleration; 1672 _acceleration = entprop.Acceleration;
1624 _rotationalVelocity = entprop.RotationalVelocity; 1673 _rotationalVelocity = entprop.RotationalVelocity;
1625 1674
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
index 6401308..f1c3b5c 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
@@ -44,72 +44,107 @@ namespace OpenSim.Region.Physics.BulletSPlugin
44{ 44{
45public class BSPrimDisplaced : BSPrim 45public class BSPrimDisplaced : BSPrim
46{ 46{
47 // 'Position' and 'Orientation' is what the simulator thinks the positions of the prim is. 47 // The purpose of this module is to do any mapping between what the simulator thinks
48 // Because Bullet needs the zero coordinate to be the center of mass of the linkset, 48 // the prim position and orientation is and what the physical position/orientation.
49 // sometimes it is necessary to displace the position the physics engine thinks 49 // This difference happens because Bullet assumes the center-of-mass is the <0,0,0>
50 // the position is. PositionDisplacement must be added and removed from the 50 // of the prim/linkset. The simulator tracks the location of the prim/linkset by
51 // position as the simulator position is stored and fetched from the physics 51 // the location of the root prim. So, if center-of-mass is anywhere but the origin
52 // engine. Similar to OrientationDisplacement. 52 // of the root prim, the physical origin is displaced from the simulator origin.
53 //
54 // This routine works by capturing the Force* setting of position/orientation/... and
55 // adjusting the simulator values (being set) into the physical values.
56 // The conversion is also done in the opposite direction (physical origin -> simulator origin).
57 //
58 // The updateParameter call is also captured and the values from the physics engine
59 // are converted into simulator origin values before being passed to the base
60 // class.
61
53 public virtual OMV.Vector3 PositionDisplacement { get; set; } 62 public virtual OMV.Vector3 PositionDisplacement { get; set; }
54 public virtual OMV.Quaternion OrientationDisplacement { get; set; } 63 public virtual OMV.Quaternion OrientationDisplacement { get; set; }
55 public virtual OMV.Vector3 CenterOfMassLocation { get; set; }
56 public virtual OMV.Vector3 GeometricCenterLocation { get; set; }
57 64
58 public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 65 public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
59 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 66 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
60 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) 67 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
61 { 68 {
62 CenterOfMassLocation = RawPosition; 69 ClearDisplacement();
63 GeometricCenterLocation = RawPosition;
64 } 70 }
65 71
66 public override Vector3 ForcePosition 72 public void ClearDisplacement()
73 {
74 PositionDisplacement = OMV.Vector3.Zero;
75 OrientationDisplacement = OMV.Quaternion.Identity;
76 }
77
78 // Set this sets and computes the displacement from the passed prim to the center-of-mass.
79 // A user set value for center-of-mass overrides whatever might be passed in here.
80 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
81 public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement)
67 { 82 {
68 get 83 Vector3 comDisp;
84 if (UserSetCenterOfMass.HasValue)
85 comDisp = (OMV.Vector3)UserSetCenterOfMass;
86 else
87 comDisp = centerOfMassDisplacement;
88
89 if (comDisp == Vector3.Zero)
69 { 90 {
70 return base.ForcePosition; 91 // If there is no diplacement. Things get reset.
92 PositionDisplacement = OMV.Vector3.Zero;
93 OrientationDisplacement = OMV.Quaternion.Identity;
71 } 94 }
72 set 95 else
73 { 96 {
74 base.ForcePosition = value; 97 // Remember the displacement from root as well as the origional rotation of the
75 CenterOfMassLocation = RawPosition; 98 // new center-of-mass.
76 GeometricCenterLocation = RawPosition; 99 PositionDisplacement = comDisp;
100 OrientationDisplacement = OMV.Quaternion.Identity;
77 } 101 }
78 } 102 }
79 103
80 public override Quaternion ForceOrientation 104 public override Vector3 ForcePosition
81 { 105 {
82 get 106 get { return base.ForcePosition; }
107 set
83 { 108 {
84 return base.ForceOrientation; 109 if (PositionDisplacement != OMV.Vector3.Zero)
110 base.ForcePosition = value - (PositionDisplacement * RawOrientation);
111 else
112 base.ForcePosition = value;
85 } 113 }
114 }
115
116 public override Quaternion ForceOrientation
117 {
118 get { return base.ForceOrientation; }
86 set 119 set
87 { 120 {
88 base.ForceOrientation = value; 121 base.ForceOrientation = value;
89 } 122 }
90 } 123 }
91 124
125 // TODO: decide if this is the right place for these variables.
126 // Somehow incorporate the optional settability by the user.
92 // Is this used? 127 // Is this used?
93 public override OMV.Vector3 CenterOfMass 128 public override OMV.Vector3 CenterOfMass
94 { 129 {
95 get { return CenterOfMassLocation; } 130 get { return RawPosition; }
96 } 131 }
97 132
98 // Is this used? 133 // Is this used?
99 public override OMV.Vector3 GeometricCenter 134 public override OMV.Vector3 GeometricCenter
100 { 135 {
101 get { return GeometricCenterLocation; } 136 get { return RawPosition; }
102 } 137 }
103 138
104
105 public override void UpdateProperties(EntityProperties entprop) 139 public override void UpdateProperties(EntityProperties entprop)
106 { 140 {
107 // Undo any center-of-mass displacement that might have been done. 141 // Undo any center-of-mass displacement that might have been done.
108 if (PositionDisplacement != OMV.Vector3.Zero) 142 if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity)
109 { 143 {
110 // Correct for any rotation around the center-of-mass 144 // Correct for any rotation around the center-of-mass
111 // TODO!!! 145 // TODO!!!
112 entprop.Position -= PositionDisplacement; 146 entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation);
147 // entprop.Rotation = something;
113 } 148 }
114 149
115 base.UpdateProperties(entprop); 150 base.UpdateProperties(entprop);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
index 9898562..d65d407 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
@@ -38,6 +38,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
38public class BSPrimLinkable : BSPrimDisplaced 38public class BSPrimLinkable : BSPrimDisplaced
39{ 39{
40 public BSLinkset Linkset { get; set; } 40 public BSLinkset Linkset { get; set; }
41 // The index of this child prim.
42 public int LinksetChildIndex { get; set; }
43
41 public BSLinksetInfo LinksetInfo { get; set; } 44 public BSLinksetInfo LinksetInfo { get; set; }
42 45
43 public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 46 public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
@@ -90,7 +93,6 @@ public class BSPrimLinkable : BSPrimDisplaced
90 DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", 93 DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
91 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); 94 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
92 return; 95 return;
93 base.delink();
94 } 96 }
95 97
96 // When simulator changes position, this might be moving a child of the linkset. 98 // When simulator changes position, this might be moving a child of the linkset.
@@ -133,7 +135,8 @@ public class BSPrimLinkable : BSPrimDisplaced
133 // When going from non-physical to physical, this re-enables the constraints that 135 // When going from non-physical to physical, this re-enables the constraints that
134 // had been automatically disabled when the mass was set to zero. 136 // had been automatically disabled when the mass was set to zero.
135 // For compound based linksets, this enables and disables interactions of the children. 137 // For compound based linksets, this enables and disables interactions of the children.
136 Linkset.Refresh(this); 138 if (Linkset != null) // null can happen during initialization
139 Linkset.Refresh(this);
137 } 140 }
138 141
139 protected override void MakeDynamic(bool makeStatic) 142 protected override void MakeDynamic(bool makeStatic)
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index f68612c..35ae44c 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -52,7 +52,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
52 { 52 {
53 bool Cancel(); 53 bool Cancel();
54 void Abort(); 54 void Abort();
55 bool Wait(TimeSpan t); 55
56 /// <summary>
57 /// Wait for the work item to complete.
58 /// </summary>
59 /// <param name='t'>The number of milliseconds to wait. Must be >= -1 (Timeout.Infinite).</param>
60 bool Wait(int t);
56 } 61 }
57 62
58 /// <summary> 63 /// <summary>
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index be6ac0a..96f650e 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -4479,6 +4479,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4479 } 4479 }
4480 } 4480 }
4481 } 4481 }
4482
4482 if (pushAllowed) 4483 if (pushAllowed)
4483 { 4484 {
4484 float distance = (PusheePos - m_host.AbsolutePosition).Length(); 4485 float distance = (PusheePos - m_host.AbsolutePosition).Length();
@@ -4507,17 +4508,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4507 applied_linear_impulse *= scaling_factor; 4508 applied_linear_impulse *= scaling_factor;
4508 4509
4509 } 4510 }
4511
4510 if (pusheeIsAvatar) 4512 if (pusheeIsAvatar)
4511 { 4513 {
4512 if (pusheeav != null) 4514 if (pusheeav != null)
4513 { 4515 {
4514 if (pusheeav.PhysicsActor != null) 4516 PhysicsActor pa = pusheeav.PhysicsActor;
4517
4518 if (pa != null)
4515 { 4519 {
4516 if (local != 0) 4520 if (local != 0)
4517 { 4521 {
4518 applied_linear_impulse *= m_host.GetWorldRotation(); 4522 applied_linear_impulse *= m_host.GetWorldRotation();
4519 } 4523 }
4520 pusheeav.PhysicsActor.AddForce(applied_linear_impulse, true); 4524
4525 pa.AddForce(applied_linear_impulse, true);
4521 } 4526 }
4522 } 4527 }
4523 } 4528 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 669cc37..bf19a42 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -595,7 +595,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
595 if (!m_coopTermination) 595 if (!m_coopTermination)
596 { 596 {
597 // If we're not co-operative terminating then try and wait for the event to complete before stopping 597 // If we're not co-operative terminating then try and wait for the event to complete before stopping
598 if (workItem.Wait(new TimeSpan((long)timeout * 100000))) 598 if (workItem.Wait(timeout))
599 return true; 599 return true;
600 } 600 }
601 else 601 else
@@ -610,7 +610,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
610 610
611 // For now, we will wait forever since the event should always cleanly terminate once LSL loop 611 // For now, we will wait forever since the event should always cleanly terminate once LSL loop
612 // checking is implemented. May want to allow a shorter timeout option later. 612 // checking is implemented. May want to allow a shorter timeout option later.
613 if (workItem.Wait(TimeSpan.MaxValue)) 613 if (workItem.Wait(Timeout.Infinite))
614 { 614 {
615 if (DebugLevel >= 1) 615 if (DebugLevel >= 1)
616 m_log.DebugFormat( 616 m_log.DebugFormat(
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
index 2ac5c31..8dd7677 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
@@ -57,8 +57,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
57 wr.Abort(); 57 wr.Abort();
58 } 58 }
59 59
60 public bool Wait(TimeSpan t) 60 public bool Wait(int t)
61 { 61 {
62 // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the
63 // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an
64 // int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8
65 // (or very likely other versions of Mono at least up until 3.0.3).
62 return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); 66 return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false);
63 } 67 }
64 } 68 }