aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Framework/Console/ConsoleUtil.cs28
-rw-r--r--OpenSim/Framework/PluginManager.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs6
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs38
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/World/Sound/SoundModule.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs11
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs10
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs9
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs36
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs41
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs83
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs21
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs17
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs238
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs3
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs81
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs28
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs120
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs13
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs41
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs7
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs8
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs11
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs160
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs278
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt64
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsActor.cs13
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs12
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs40
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs88
-rw-r--r--OpenSim/Region/UserStatistics/WebStatsModule.cs45
-rw-r--r--OpenSim/Server/Base/ServerUtils.cs56
36 files changed, 1125 insertions, 507 deletions
diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs
index 16a63e0..dff956a 100644
--- a/OpenSim/Framework/Console/ConsoleUtil.cs
+++ b/OpenSim/Framework/Console/ConsoleUtil.cs
@@ -97,7 +97,7 @@ namespace OpenSim.Framework.Console
97 if (!UUID.TryParse(rawUuid, out uuid)) 97 if (!UUID.TryParse(rawUuid, out uuid))
98 { 98 {
99 if (console != null) 99 if (console != null)
100 console.OutputFormat("{0} is not a valid uuid", rawUuid); 100 console.OutputFormat("ERROR: {0} is not a valid uuid", rawUuid);
101 101
102 return false; 102 return false;
103 } 103 }
@@ -110,7 +110,7 @@ namespace OpenSim.Framework.Console
110 if (!uint.TryParse(rawLocalId, out localId)) 110 if (!uint.TryParse(rawLocalId, out localId))
111 { 111 {
112 if (console != null) 112 if (console != null)
113 console.OutputFormat("{0} is not a valid local id", localId); 113 console.OutputFormat("ERROR: {0} is not a valid local id", localId);
114 114
115 return false; 115 return false;
116 } 116 }
@@ -118,7 +118,7 @@ namespace OpenSim.Framework.Console
118 if (localId == 0) 118 if (localId == 0)
119 { 119 {
120 if (console != null) 120 if (console != null)
121 console.OutputFormat("{0} is not a valid local id - it must be greater than 0", localId); 121 console.OutputFormat("ERROR: {0} is not a valid local id - it must be greater than 0", localId);
122 122
123 return false; 123 return false;
124 } 124 }
@@ -150,10 +150,30 @@ namespace OpenSim.Framework.Console
150 } 150 }
151 151
152 if (console != null) 152 if (console != null)
153 console.OutputFormat("{0} is not a valid UUID or local id", rawId); 153 console.OutputFormat("ERROR: {0} is not a valid UUID or local id", rawId);
154 154
155 return false; 155 return false;
156 } 156 }
157
158 /// <summary>
159 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
160 /// </summary>
161 /// <param name='console'>Can be null if no console is available.</param>
162 /// <param name='rawConsoleVector'>/param>
163 /// <param name='vector'></param>
164 /// <returns></returns>
165 public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
166 {
167 if (!int.TryParse(rawConsoleInt, out i))
168 {
169 if (console != null)
170 console.OutputFormat("ERROR: {0} is not a valid integer", rawConsoleInt);
171
172 return false;
173 }
174
175 return true;
176 }
157 177
158 /// <summary> 178 /// <summary>
159 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 179 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
diff --git a/OpenSim/Framework/PluginManager.cs b/OpenSim/Framework/PluginManager.cs
index 23d5945..00263f5 100644
--- a/OpenSim/Framework/PluginManager.cs
+++ b/OpenSim/Framework/PluginManager.cs
@@ -92,6 +92,7 @@ namespace OpenSim.Framework
92 // Attempt to install the plugin disabled 92 // Attempt to install the plugin disabled
93 if (Install(ps, pack) == true) 93 if (Install(ps, pack) == true)
94 { 94 {
95 MainConsole.Instance.Output("Ignore the following error...");
95 PluginRegistry.Update(ps); 96 PluginRegistry.Update(ps);
96 Addin addin = PluginRegistry.GetAddin(aentry.Addin.Id); 97 Addin addin = PluginRegistry.GetAddin(aentry.Addin.Id);
97 PluginRegistry.DisableAddin(addin.Id); 98 PluginRegistry.DisableAddin(addin.Id);
@@ -479,6 +480,7 @@ namespace OpenSim.Framework
479 ConsoleProgressStatus ps = new ConsoleProgressStatus(false); 480 ConsoleProgressStatus ps = new ConsoleProgressStatus(false);
480 if (!AddinManager.AddinEngine.IsAddinLoaded(addin.Id)) 481 if (!AddinManager.AddinEngine.IsAddinLoaded(addin.Id))
481 { 482 {
483 MainConsole.Instance.Output("Ignore the following error...");
482 AddinManager.Registry.Rebuild(ps); 484 AddinManager.Registry.Rebuild(ps);
483 AddinManager.AddinEngine.LoadAddin(ps, addin.Id); 485 AddinManager.AddinEngine.LoadAddin(ps, addin.Id);
484 } 486 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 8e0b72f..c0daba2 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -12077,11 +12077,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12077 if (logPacket) 12077 if (logPacket)
12078 m_log.DebugFormat( 12078 m_log.DebugFormat(
12079 "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}", 12079 "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}",
12080 Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type); 12080 Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name, packet.Type);
12081 } 12081 }
12082 12082
12083 if (!ProcessPacketMethod(packet)) 12083 if (!ProcessPacketMethod(packet))
12084 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); 12084 m_log.WarnFormat(
12085 "[CLIENT]: Unhandled packet {0} from {1} ({2}) in {3}. Ignoring.",
12086 packet.Type, Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name);
12085 } 12087 }
12086 12088
12087 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) 12089 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
index f8ec6de..7871eda 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
@@ -71,7 +71,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
71 71
72 #region Internal functions 72 #region Internal functions
73 73
74 public AssetMetadata FetchMetadata(string url, UUID assetID) 74 private AssetMetadata FetchMetadata(string url, UUID assetID)
75 { 75 {
76 if (!url.EndsWith("/") && !url.EndsWith("=")) 76 if (!url.EndsWith("/") && !url.EndsWith("="))
77 url = url + "/"; 77 url = url + "/";
@@ -86,6 +86,27 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
86 return meta; 86 return meta;
87 } 87 }
88 88
89 private AssetBase FetchAsset(string url, UUID assetID)
90 {
91 // Test if it's already here
92 AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
93 if (asset == null)
94 {
95 if (!url.EndsWith("/") && !url.EndsWith("="))
96 url = url + "/";
97
98 asset = m_scene.AssetService.Get(url + assetID.ToString());
99
100 //if (asset != null)
101 // m_log.DebugFormat("[HG ASSET MAPPER]: Fetched asset {0} of type {1} from {2} ", assetID, asset.Metadata.Type, url);
102 //else
103 // m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetch asset {0} from {1} ", assetID, url);
104
105 }
106
107 return asset;
108 }
109
89 public bool PostAsset(string url, AssetBase asset) 110 public bool PostAsset(string url, AssetBase asset)
90 { 111 {
91 if (asset != null) 112 if (asset != null)
@@ -228,11 +249,22 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
228 if (meta == null) 249 if (meta == null)
229 return; 250 return;
230 251
231 // The act of gathering UUIDs downloads the assets from the remote server 252 // The act of gathering UUIDs downloads some assets from the remote server
253 // but not all...
232 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); 254 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
233 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL); 255 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL);
234 uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids); 256 uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids);
235 257 m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", ids.Count);
258 bool success = true;
259 foreach (UUID uuid in ids.Keys)
260 if (FetchAsset(userAssetURL, uuid) == null)
261 success = false;
262
263 // maybe all pieces got here...
264 if (!success)
265 m_log.DebugFormat("[HG ASSET MAPPER]: Problems getting item {0} from asset server {1}", assetID, userAssetURL);
266 else
267 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully got item {0} from asset server {1}", assetID, userAssetURL);
236 } 268 }
237 269
238 270
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
index 86e7004..77e8b00 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
@@ -181,6 +181,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
181 181
182 m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); 182 m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query);
183 183
184 // searhc the user accounts service
184 List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); 185 List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query);
185 186
186 List<UserData> users = new List<UserData>(); 187 List<UserData> users = new List<UserData>();
@@ -196,6 +197,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
196 } 197 }
197 } 198 }
198 199
200 // search the local cache
201 foreach (UserData data in m_UserCache.Values)
202 if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null &&
203 (data.FirstName.StartsWith(query) || data.LastName.StartsWith(query)))
204 users.Add(data);
205
199 AddAdditionalUsers(avatarID, query, users); 206 AddAdditionalUsers(avatarID, query, users);
200 207
201 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); 208 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply);
@@ -433,6 +440,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
433 public void AddUser(UUID uuid, string first, string last, string homeURL) 440 public void AddUser(UUID uuid, string first, string last, string homeURL)
434 { 441 {
435 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); 442 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
443 if (homeURL == string.Empty)
444 return;
445
436 AddUser(uuid, homeURL + ";" + first + " " + last); 446 AddUser(uuid, homeURL + ";" + first + " " + last);
437 } 447 }
438 448
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
index 089fcda..883045a 100644
--- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
+++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
@@ -76,7 +76,7 @@ namespace OpenSim.Region.CoreModules.World.Sound
76 76
77 public void RemoveRegion(Scene scene) 77 public void RemoveRegion(Scene scene)
78 { 78 {
79 m_scene.EventManager.OnClientLogin -= OnNewClient; 79 m_scene.EventManager.OnNewClient -= OnNewClient;
80 } 80 }
81 81
82 public void RegionLoaded(Scene scene) 82 public void RegionLoaded(Scene scene)
@@ -85,7 +85,7 @@ namespace OpenSim.Region.CoreModules.World.Sound
85 return; 85 return;
86 86
87 m_scene = scene; 87 m_scene = scene;
88 m_scene.EventManager.OnClientLogin += OnNewClient; 88 m_scene.EventManager.OnNewClient += OnNewClient;
89 89
90 m_scene.RegisterModuleInterface<ISoundModule>(this); 90 m_scene.RegisterModuleInterface<ISoundModule>(this);
91 } 91 }
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
index 9458079..d18571c 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
@@ -26,9 +26,10 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Threading;
30using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection; 31using System.Reflection;
32using System.Threading;
32using log4net; 33using log4net;
33using OpenMetaverse; 34using OpenMetaverse;
34using OpenSim.Framework; 35using OpenSim.Framework;
@@ -113,6 +114,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation
113 if (m_scenePresence.IsChildAgent) 114 if (m_scenePresence.IsChildAgent)
114 return; 115 return;
115 116
117// m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Removing animation {0} for {1}", animID, m_scenePresence.Name);
118
116 if (m_animations.Remove(animID)) 119 if (m_animations.Remove(animID))
117 SendAnimPack(); 120 SendAnimPack();
118 } 121 }
@@ -519,6 +522,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation
519 if (m_scenePresence.IsChildAgent) 522 if (m_scenePresence.IsChildAgent)
520 return; 523 return;
521 524
525// m_log.DebugFormat(
526// "[SCENE PRESENCE ANIMATOR]: Sending anim pack with animations '{0}', sequence '{1}', uuids '{2}'",
527// string.Join(",", Array.ConvertAll<UUID, string>(animations, a => a.ToString())),
528// string.Join(",", Array.ConvertAll<int, string>(seqs, s => s.ToString())),
529// string.Join(",", Array.ConvertAll<UUID, string>(objectIDs, o => o.ToString())));
530
522 m_scenePresence.Scene.ForEachClient( 531 m_scenePresence.Scene.ForEachClient(
523 delegate(IClientAPI client) 532 delegate(IClientAPI client)
524 { 533 {
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index c9d1205..65c50bf 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -683,12 +683,10 @@ namespace OpenSim.Region.Framework.Scenes
683 itemCopy.SalePrice = item.SalePrice; 683 itemCopy.SalePrice = item.SalePrice;
684 itemCopy.SaleType = item.SaleType; 684 itemCopy.SaleType = item.SaleType;
685 685
686 if (AddInventoryItem(itemCopy)) 686 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
687 { 687 if (invAccess != null)
688 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>(); 688 invAccess.TransferInventoryAssets(itemCopy, senderId, recipient);
689 if (invAccess != null) 689 AddInventoryItem(itemCopy);
690 Util.FireAndForget(delegate { invAccess.TransferInventoryAssets(itemCopy, senderId, recipient); });
691 }
692 690
693 if (!Permissions.BypassPermissions()) 691 if (!Permissions.BypassPermissions())
694 { 692 {
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 2191cfa..c746690 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -2895,11 +2895,14 @@ namespace OpenSim.Region.Framework.Scenes
2895 2895
2896 public void PhysicsOutOfBounds(Vector3 pos) 2896 public void PhysicsOutOfBounds(Vector3 pos)
2897 { 2897 {
2898 m_log.Error("[PHYSICS]: Physical Object went out of bounds."); 2898 // Note: This is only being called on the root prim at this time.
2899
2900 m_log.ErrorFormat(
2901 "[SCENE OBJECT PART]: Physical object {0}, localID {1} went out of bounds at {2} in {3}. Stopping at {4} and making non-physical.",
2902 Name, LocalId, pos, ParentGroup.Scene.Name, AbsolutePosition);
2899 2903
2900 RemFlag(PrimFlags.Physics); 2904 RemFlag(PrimFlags.Physics);
2901 DoPhysicsPropertyUpdate(false, true); 2905 DoPhysicsPropertyUpdate(false, true);
2902 //ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
2903 } 2906 }
2904 2907
2905 public void PhysicsRequestingTerseUpdate() 2908 public void PhysicsRequestingTerseUpdate()
@@ -4549,7 +4552,7 @@ namespace OpenSim.Region.Framework.Scenes
4549 if (ParentGroup.RootPart == this) 4552 if (ParentGroup.RootPart == this)
4550 AngularVelocity = new Vector3(0, 0, 0); 4553 AngularVelocity = new Vector3(0, 0, 0);
4551 } 4554 }
4552 else 4555 else if (SetVD != wasVD)
4553 { 4556 {
4554 if (ParentGroup.Scene.CollidablePrims) 4557 if (ParentGroup.Scene.CollidablePrims)
4555 { 4558 {
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 7f07d73..1250a11 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -214,8 +214,6 @@ namespace OpenSim.Region.Framework.Scenes
214 214
215 private Quaternion m_headrotation = Quaternion.Identity; 215 private Quaternion m_headrotation = Quaternion.Identity;
216 216
217 private string m_nextSitAnimation = String.Empty;
218
219 //PauPaw:Proper PID Controler for autopilot************ 217 //PauPaw:Proper PID Controler for autopilot************
220 public bool MovingToTarget { get; private set; } 218 public bool MovingToTarget { get; private set; }
221 public Vector3 MoveToPositionTarget { get; private set; } 219 public Vector3 MoveToPositionTarget { get; private set; }
@@ -2120,25 +2118,10 @@ namespace OpenSim.Region.Framework.Scenes
2120 StandUp(); 2118 StandUp();
2121 } 2119 }
2122 2120
2123// if (!String.IsNullOrEmpty(sitAnimation))
2124// {
2125// m_nextSitAnimation = sitAnimation;
2126// }
2127// else
2128// {
2129 m_nextSitAnimation = "SIT";
2130// }
2131
2132 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID);
2133 SceneObjectPart part = FindNextAvailableSitTarget(targetID); 2121 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
2134 2122
2135 if (part != null) 2123 if (part != null)
2136 { 2124 {
2137 if (!String.IsNullOrEmpty(part.SitAnimation))
2138 {
2139 m_nextSitAnimation = part.SitAnimation;
2140 }
2141
2142 m_requestedSitTargetID = part.LocalId; 2125 m_requestedSitTargetID = part.LocalId;
2143 m_requestedSitTargetUUID = targetID; 2126 m_requestedSitTargetUUID = targetID;
2144 2127
@@ -2353,18 +2336,6 @@ namespace OpenSim.Region.Framework.Scenes
2353 2336
2354 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) 2337 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID)
2355 { 2338 {
2356 if (!String.IsNullOrEmpty(m_nextSitAnimation))
2357 {
2358 HandleAgentSit(remoteClient, agentID, m_nextSitAnimation);
2359 }
2360 else
2361 {
2362 HandleAgentSit(remoteClient, agentID, "SIT");
2363 }
2364 }
2365
2366 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID, string sitAnimation)
2367 {
2368 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); 2339 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
2369 2340
2370 if (part != null) 2341 if (part != null)
@@ -2436,7 +2407,12 @@ namespace OpenSim.Region.Framework.Scenes
2436 2407
2437 Velocity = Vector3.Zero; 2408 Velocity = Vector3.Zero;
2438 RemoveFromPhysicalScene(); 2409 RemoveFromPhysicalScene();
2439 2410
2411 String sitAnimation = "SIT";
2412 if (!String.IsNullOrEmpty(part.SitAnimation))
2413 {
2414 sitAnimation = part.SitAnimation;
2415 }
2440 Animator.TrySetMovementAnimation(sitAnimation); 2416 Animator.TrySetMovementAnimation(sitAnimation);
2441 SendAvatarDataToAllAgents(); 2417 SendAvatarDataToAllAgents();
2442 } 2418 }
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs
index 093cbd2..8eb3191 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs
@@ -78,6 +78,26 @@ namespace OpenSim.Region.Framework.Scenes.Tests
78 } 78 }
79 79
80 [Test] 80 [Test]
81 public void TestSetNonPhysicsVolumeDetectSinglePrim()
82 {
83 TestHelpers.InMethod();
84
85 m_scene.AddSceneObject(m_so1);
86
87 SceneObjectPart rootPart = m_so1.RootPart;
88 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
89
90 m_so1.ScriptSetVolumeDetect(true);
91
92// Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags);
93 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom));
94
95 m_so1.ScriptSetVolumeDetect(false);
96
97 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
98 }
99
100 [Test]
81 public void TestSetPhysicsSinglePrim() 101 public void TestSetPhysicsSinglePrim()
82 { 102 {
83 TestHelpers.InMethod(); 103 TestHelpers.InMethod();
@@ -89,13 +109,32 @@ namespace OpenSim.Region.Framework.Scenes.Tests
89 109
90 m_so1.ScriptSetPhysicsStatus(true); 110 m_so1.ScriptSetPhysicsStatus(true);
91 111
92// Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags);
93 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); 112 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics));
94 113
95 m_so1.ScriptSetPhysicsStatus(false); 114 m_so1.ScriptSetPhysicsStatus(false);
96 115
97 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); 116 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
98 } 117 }
118
119 [Test]
120 public void TestSetPhysicsVolumeDetectSinglePrim()
121 {
122 TestHelpers.InMethod();
123
124 m_scene.AddSceneObject(m_so1);
125
126 SceneObjectPart rootPart = m_so1.RootPart;
127 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
128
129 m_so1.ScriptSetPhysicsStatus(true);
130 m_so1.ScriptSetVolumeDetect(true);
131
132 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom | PrimFlags.Physics));
133
134 m_so1.ScriptSetVolumeDetect(false);
135
136 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics));
137 }
99 138
100 [Test] 139 [Test]
101 public void TestSetPhysicsLinkset() 140 public void TestSetPhysicsLinkset()
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 21aa9be..0defb24 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -105,12 +105,12 @@ public sealed class BSCharacter : BSPhysObject
105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
107 107
108 // do actual create at taint time 108 // do actual creation in taint time
109 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 109 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
110 { 110 {
111 DetailLog("{0},BSCharacter.create,taint", LocalID); 111 DetailLog("{0},BSCharacter.create,taint", LocalID);
112 // New body and shape into PhysBody and PhysShape 112 // New body and shape into PhysBody and PhysShape
113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); 113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
114 114
115 SetPhysicalProperties(); 115 SetPhysicalProperties();
116 }); 116 });
@@ -124,7 +124,9 @@ public sealed class BSCharacter : BSPhysObject
124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
125 { 125 {
126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
127 PhysBody.Clear();
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 128 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
129 PhysShape.Clear();
128 }); 130 });
129 } 131 }
130 132
@@ -165,9 +167,8 @@ public sealed class BSCharacter : BSPhysObject
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 167 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
166 168
167 // Do this after the object has been added to the world 169 // Do this after the object has been added to the world
168 BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr, 170 PhysBody.collisionType = CollisionType.Avatar;
169 (uint)CollisionFilterGroups.AvatarGroup, 171 PhysBody.ApplyCollisionMask();
170 (uint)CollisionFilterGroups.AvatarMask);
171 } 172 }
172 173
173 public override void RequestPhysicsterseUpdate() 174 public override void RequestPhysicsterseUpdate()
@@ -187,6 +188,11 @@ public sealed class BSCharacter : BSPhysObject
187 set { 188 set {
188 // When an avatar's size is set, only the height is changed. 189 // When an avatar's size is set, only the height is changed.
189 _size = value; 190 _size = value;
191 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
192 // replace with the default values.
193 if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
194 if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
195
190 ComputeAvatarScale(_size); 196 ComputeAvatarScale(_size);
191 ComputeAvatarVolumeAndMass(); 197 ComputeAvatarVolumeAndMass();
192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 198 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
@@ -194,15 +200,18 @@ public sealed class BSCharacter : BSPhysObject
194 200
195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 201 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
196 { 202 {
197 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 203 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
198 UpdatePhysicalMassProperties(RawMass); 204 {
205 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
206 UpdatePhysicalMassProperties(RawMass);
207 // Make sure this change appears as a property update event
208 BulletSimAPI.PushUpdate2(PhysBody.ptr);
209 }
199 }); 210 });
200 211
201 } 212 }
202 } 213 }
203 214
204 public override OMV.Vector3 Scale { get; set; }
205
206 public override PrimitiveBaseShape Shape 215 public override PrimitiveBaseShape Shape
207 { 216 {
208 set { BaseShape = value; } 217 set { BaseShape = value; }
@@ -236,7 +245,8 @@ public sealed class BSCharacter : BSPhysObject
236 // Zero some other properties directly into the physics engine 245 // Zero some other properties directly into the physics engine
237 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
238 { 247 {
239 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 248 if (PhysBody.HasPhysicalBody)
249 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
240 }); 250 });
241 } 251 }
242 public override void ZeroAngularMotion(bool inTaintTime) 252 public override void ZeroAngularMotion(bool inTaintTime)
@@ -245,10 +255,13 @@ public sealed class BSCharacter : BSPhysObject
245 255
246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 256 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
247 { 257 {
248 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 258 if (PhysBody.HasPhysicalBody)
249 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 259 {
250 // The next also get rid of applied linear force but the linear velocity is untouched. 260 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
251 BulletSimAPI.ClearForces2(PhysBody.ptr); 261 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
262 // The next also get rid of applied linear force but the linear velocity is untouched.
263 BulletSimAPI.ClearForces2(PhysBody.ptr);
264 }
252 }); 265 });
253 } 266 }
254 267
@@ -273,7 +286,8 @@ public sealed class BSCharacter : BSPhysObject
273 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 286 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
274 { 287 {
275 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 288 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 289 if (PhysBody.HasPhysicalBody)
290 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
277 }); 291 });
278 } 292 }
279 } 293 }
@@ -332,7 +346,8 @@ public sealed class BSCharacter : BSPhysObject
332 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 346 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
333 { 347 {
334 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 348 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 349 if (PhysBody.HasPhysicalBody)
350 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
336 }); 351 });
337 ret = true; 352 ret = true;
338 } 353 }
@@ -359,7 +374,8 @@ public sealed class BSCharacter : BSPhysObject
359 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 374 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
360 { 375 {
361 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 376 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
362 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 377 if (PhysBody.HasPhysicalBody)
378 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
363 }); 379 });
364 } 380 }
365 } 381 }
@@ -398,7 +414,8 @@ public sealed class BSCharacter : BSPhysObject
398 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) 414 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
399 { 415 {
400 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 416 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
401 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); 417 if (PhysBody.HasPhysicalBody)
418 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
402 } 419 }
403 } 420 }
404 else 421 else
@@ -406,7 +423,8 @@ public sealed class BSCharacter : BSPhysObject
406 if (_currentFriction != PhysicsScene.Params.avatarFriction) 423 if (_currentFriction != PhysicsScene.Params.avatarFriction)
407 { 424 {
408 _currentFriction = PhysicsScene.Params.avatarFriction; 425 _currentFriction = PhysicsScene.Params.avatarFriction;
409 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); 426 if (PhysBody.HasPhysicalBody)
427 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
410 } 428 }
411 } 429 }
412 _velocity = value; 430 _velocity = value;
@@ -443,8 +461,11 @@ public sealed class BSCharacter : BSPhysObject
443 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 461 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
444 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 462 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
445 { 463 {
446 // _position = BulletSimAPI.GetPosition2(BSBody.ptr); 464 if (PhysBody.HasPhysicalBody)
447 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 465 {
466 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
467 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
468 }
448 }); 469 });
449 } 470 }
450 } 471 }
@@ -517,10 +538,13 @@ public sealed class BSCharacter : BSPhysObject
517 _floatOnWater = value; 538 _floatOnWater = value;
518 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 539 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
519 { 540 {
520 if (_floatOnWater) 541 if (PhysBody.HasPhysicalBody)
521 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 542 {
522 else 543 if (_floatOnWater)
523 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 544 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
545 else
546 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
547 }
524 }); 548 });
525 } 549 }
526 } 550 }
@@ -553,7 +577,8 @@ public sealed class BSCharacter : BSPhysObject
553 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 577 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
554 // Buoyancy is faked by changing the gravity applied to the object 578 // Buoyancy is faked by changing the gravity applied to the object
555 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 579 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
556 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 580 if (PhysBody.HasPhysicalBody)
581 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
557 } 582 }
558 } 583 }
559 584
@@ -599,7 +624,8 @@ public sealed class BSCharacter : BSPhysObject
599 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() 624 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
600 { 625 {
601 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 626 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
602 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 627 if (PhysBody.HasPhysicalBody)
628 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
603 }); 629 });
604 } 630 }
605 else 631 else
@@ -616,9 +642,6 @@ public sealed class BSCharacter : BSPhysObject
616 642
617 private void ComputeAvatarScale(OMV.Vector3 size) 643 private void ComputeAvatarScale(OMV.Vector3 size)
618 { 644 {
619 // The 'size' given by the simulator is the mid-point of the avatar
620 // and X and Y are unspecified.
621
622 OMV.Vector3 newScale = size; 645 OMV.Vector3 newScale = size;
623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; 646 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; 647 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 65fac00..6b1e304 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -57,7 +57,7 @@ public abstract class BSConstraint : IDisposable
57 if (m_enabled) 57 if (m_enabled)
58 { 58 {
59 m_enabled = false; 59 m_enabled = false;
60 if (m_constraint.ptr != IntPtr.Zero) 60 if (m_constraint.HasPhysicalConstraint)
61 { 61 {
62 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); 62 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
63 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", 63 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
@@ -65,7 +65,7 @@ public abstract class BSConstraint : IDisposable
65 m_body1.ID, m_body1.ptr.ToString("X"), 65 m_body1.ID, m_body1.ptr.ToString("X"),
66 m_body2.ID, m_body2.ptr.ToString("X"), 66 m_body2.ID, m_body2.ptr.ToString("X"),
67 success); 67 success);
68 m_constraint.ptr = System.IntPtr.Zero; 68 m_constraint.Clear();
69 } 69 }
70 } 70 }
71 } 71 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
index 23ef052..b073555 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -65,7 +65,7 @@ public sealed class BSConstraint6Dof : BSConstraint
65 m_world = world; 65 m_world = world;
66 m_body1 = obj1; 66 m_body1 = obj1;
67 m_body2 = obj2; 67 m_body2 = obj2;
68 if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) 68 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
69 { 69 {
70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
71 BSScene.DetailLogZero, world.worldID, 71 BSScene.DetailLogZero, world.worldID,
@@ -83,7 +83,7 @@ public sealed class BSConstraint6Dof : BSConstraint
83 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", 83 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
84 BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"), 84 BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"),
85 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 85 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
86 if (m_constraint.ptr == IntPtr.Zero) 86 if (!m_constraint.HasPhysicalConstraint)
87 { 87 {
88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", 88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
89 LogHeader, obj1.ID, obj2.ID); 89 LogHeader, obj1.ID, obj2.ID);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index fa3110c..82e829e 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -570,8 +570,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
570 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); 570 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
571 BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr); 571 BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr);
572 572
573 VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}", 573 VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}",
574 Prim.LocalID, friction, localInertia, angularDamping); 574 Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping);
575 } 575 }
576 else 576 else
577 { 577 {
@@ -818,6 +818,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
818 + hoverContribution 818 + hoverContribution
819 + limitMotorUpContribution; 819 + limitMotorUpContribution;
820 820
821 Vector3 newForce = buoyancyContribution;
822
821 // If not changing some axis, reduce out velocity 823 // If not changing some axis, reduce out velocity
822 if ((m_flags & (VehicleFlag.NO_X)) != 0) 824 if ((m_flags & (VehicleFlag.NO_X)) != 0)
823 newVelocity.X = 0; 825 newVelocity.X = 0;
@@ -845,7 +847,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
845 VehicleVelocity = newVelocity; 847 VehicleVelocity = newVelocity;
846 848
847 // Other linear forces are applied as forces. 849 // Other linear forces are applied as forces.
848 Vector3 totalDownForce = buoyancyContribution * m_vehicleMass; 850 Vector3 totalDownForce = newForce * m_vehicleMass;
849 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f)) 851 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
850 { 852 {
851 VehicleAddForce(totalDownForce); 853 VehicleAddForce(totalDownForce);
@@ -991,8 +993,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
991 993
992 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 994 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
993 { 995 {
994 // If the vehicle is motoring into the sky, get it going back down. 996 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
995 float distanceAboveGround = VehiclePosition.Z - GetTerrainHeight(VehiclePosition); 997 float distanceAboveGround = VehiclePosition.Z - targetHeight;
996 // Not colliding if the vehicle is off the ground 998 // Not colliding if the vehicle is off the ground
997 if (!Prim.IsColliding) 999 if (!Prim.IsColliding)
998 { 1000 {
@@ -1005,8 +1007,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1005 // has a decay factor. This says this force should 1007 // has a decay factor. This says this force should
1006 // be computed with a motor. 1008 // be computed with a motor.
1007 // TODO: add interaction with banking. 1009 // TODO: add interaction with banking.
1008 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 1010 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1009 Prim.LocalID, distanceAboveGround, ret); 1011 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
1010 } 1012 }
1011 return ret; 1013 return ret;
1012 } 1014 }
@@ -1055,7 +1057,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1055 // TODO: Should this be applied as an angular force (torque)? 1057 // TODO: Should this be applied as an angular force (torque)?
1056 if (!m_lastAngularCorrection.ApproxEquals(Vector3.Zero, 0.01f)) 1058 if (!m_lastAngularCorrection.ApproxEquals(Vector3.Zero, 0.01f))
1057 { 1059 {
1058 Vector3 scaledCorrection = m_lastAngularCorrection * pTimestep; 1060 // DEBUG DEBUG DEBUG: optionally scale the angular velocity. Debugging SL vs ODE turning functions.
1061 Vector3 scaledCorrection = m_lastAngularCorrection;
1062 if (PhysicsScene.VehicleScaleAngularVelocityByTimestep)
1063 scaledCorrection *= pTimestep;
1059 VehicleRotationalVelocity = scaledCorrection; 1064 VehicleRotationalVelocity = scaledCorrection;
1060 1065
1061 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5},scaledCorr={6}", 1066 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5},scaledCorr={6}",
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 0df4310..ce0fbe6 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -32,6 +32,14 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35
36// A BSPrim can get individual information about its linkedness attached
37// to it through an instance of a subclass of LinksetInfo.
38// Each type of linkset will define the information needed for its type.
39public abstract class BSLinksetInfo
40{
41}
42
35public abstract class BSLinkset 43public abstract class BSLinkset
36{ 44{
37 // private static string LogHeader = "[BULLETSIM LINKSET]"; 45 // private static string LogHeader = "[BULLETSIM LINKSET]";
@@ -116,7 +124,7 @@ public abstract class BSLinkset
116 get { return ComputeLinksetGeometricCenter(); } 124 get { return ComputeLinksetGeometricCenter(); }
117 } 125 }
118 126
119 protected void Initialize(BSScene scene, BSPhysObject parent) 127 protected BSLinkset(BSScene scene, BSPhysObject parent)
120 { 128 {
121 // A simple linkset of one (no children) 129 // A simple linkset of one (no children)
122 LinksetID = m_nextLinksetID++; 130 LinksetID = m_nextLinksetID++;
@@ -127,6 +135,7 @@ public abstract class BSLinkset
127 LinksetRoot = parent; 135 LinksetRoot = parent;
128 m_children = new HashSet<BSPhysObject>(); 136 m_children = new HashSet<BSPhysObject>();
129 m_mass = parent.RawMass; 137 m_mass = parent.RawMass;
138 Rebuilding = false;
130 } 139 }
131 140
132 // Link to a linkset where the child knows the parent. 141 // Link to a linkset where the child knows the parent.
@@ -219,7 +228,7 @@ public abstract class BSLinkset
219 // I am the root of a linkset and a new child is being added 228 // I am the root of a linkset and a new child is being added
220 // Called while LinkActivity is locked. 229 // Called while LinkActivity is locked.
221 protected abstract void AddChildToLinkset(BSPhysObject child); 230 protected abstract void AddChildToLinkset(BSPhysObject child);
222 231
223 // I am the root of a linkset and one of my children is being removed. 232 // I am the root of a linkset and one of my children is being removed.
224 // Safe to call even if the child is not really in my linkset. 233 // Safe to call even if the child is not really in my linkset.
225 protected abstract void RemoveChildFromLinkset(BSPhysObject child); 234 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
@@ -229,6 +238,10 @@ public abstract class BSLinkset
229 // May be called at runtime or taint-time. 238 // May be called at runtime or taint-time.
230 public abstract void Refresh(BSPhysObject requestor); 239 public abstract void Refresh(BSPhysObject requestor);
231 240
241 // Flag denoting the linkset is in the process of being rebuilt.
242 // Used to know not the schedule a rebuild in the middle of a rebuild.
243 protected bool Rebuilding { get; set; }
244
232 // The object is going dynamic (physical). Do any setup necessary 245 // The object is going dynamic (physical). Do any setup necessary
233 // for a dynamic linkset. 246 // for a dynamic linkset.
234 // Only the state of the passed object can be modified. The rest of the linkset 247 // Only the state of the passed object can be modified. The rest of the linkset
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index 1f7c398..2189468 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -32,18 +32,43 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35
36// When a child is linked, the relationship position of the child to the parent
37// is remembered so the child's world position can be recomputed when it is
38// removed from the linkset.
39sealed class BSLinksetCompoundInfo : BSLinksetInfo
40{
41 public OMV.Vector3 OffsetPos;
42 public OMV.Quaternion OffsetRot;
43 public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r)
44 {
45 OffsetPos = p;
46 OffsetRot = r;
47 }
48 public override string ToString()
49 {
50 StringBuilder buff = new StringBuilder();
51 buff.Append("<p=");
52 buff.Append(OffsetPos.ToString());
53 buff.Append(",r=");
54 buff.Append(OffsetRot.ToString());
55 buff.Append(">");
56 return buff.ToString();
57 }
58};
59
35public sealed class BSLinksetCompound : BSLinkset 60public sealed class BSLinksetCompound : BSLinkset
36{ 61{
37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; 62 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38 63
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent) 64 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 { 65 {
41 base.Initialize(scene, parent);
42 } 66 }
43 67
44 // For compound implimented linksets, if there are children, use compound shape for the root. 68 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 69 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
46 { 70 {
71 // Returning 'unknown' means we don't have a preference.
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 72 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren) 73 if (IsRoot(requestor) && HasAnyChildren)
49 { 74 {
@@ -55,23 +80,27 @@ public sealed class BSLinksetCompound : BSLinkset
55 80
56 // When physical properties are changed the linkset needs to recalculate 81 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties. 82 // its internal properties.
58 // This is queued in the 'post taint' queue so the
59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor) 83 public override void Refresh(BSPhysObject requestor)
61 { 84 {
62 // External request for Refresh (from BSPrim) doesn't need to do anything 85 // External request for Refresh (from BSPrim) doesn't need to do anything
63 // InternalRefresh(requestor); 86 // InternalRefresh(requestor);
64 } 87 }
65 88
89 // Schedule a refresh to happen after all the other taint processing.
66 private void InternalRefresh(BSPhysObject requestor) 90 private void InternalRefresh(BSPhysObject requestor)
67 { 91 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); 92 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1},rebuilding={2}",
69 // Queue to happen after all the other taint processing 93 LinksetRoot.LocalID, requestor.LocalID, Rebuilding);
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() 94 // When rebuilding, it is possible to set properties that would normally require a rebuild.
95 // If already rebuilding, don't request another rebuild.
96 if (!Rebuilding)
71 { 97 {
72 if (IsRoot(requestor) && HasAnyChildren) 98 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
73 RecomputeLinksetCompound(); 99 {
74 }); 100 if (IsRoot(requestor) && HasAnyChildren)
101 RecomputeLinksetCompound();
102 });
103 }
75 } 104 }
76 105
77 // The object is going dynamic (physical). Do any setup necessary 106 // The object is going dynamic (physical). Do any setup necessary
@@ -84,12 +113,24 @@ public sealed class BSLinksetCompound : BSLinkset
84 { 113 {
85 bool ret = false; 114 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 115 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child)) 116 if (IsRoot(child))
117 {
118 // The root is going dynamic. Make sure mass is properly set.
119 m_mass = ComputeLinksetMass();
120 if (HasAnyChildren)
121 InternalRefresh(LinksetRoot);
122 }
123 else
88 { 124 {
89 // The origional prims are removed from the world as the shape of the root compound 125 // The origional prims are removed from the world as the shape of the root compound
90 // shape takes over. 126 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 127 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 128 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
129 // We don't want collisions from the old linkset children.
130 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
131
132 child.PhysBody.collisionType = CollisionType.LinksetChild;
133
93 ret = true; 134 ret = true;
94 } 135 }
95 return ret; 136 return ret;
@@ -104,11 +145,19 @@ public sealed class BSLinksetCompound : BSLinkset
104 { 145 {
105 bool ret = false; 146 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 147 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child)) 148 if (IsRoot(child))
149 {
150 if (HasAnyChildren)
151 InternalRefresh(LinksetRoot);
152 }
153 else
108 { 154 {
109 // The non-physical children can come back to life. 155 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 156 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay. 157
158 child.PhysBody.collisionType = CollisionType.LinksetChild;
159
160 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false); 161 BulletSimAPI.Activate2(child.PhysBody.ptr, false);
113 ret = true; 162 ret = true;
114 } 163 }
@@ -146,20 +195,58 @@ public sealed class BSLinksetCompound : BSLinkset
146 195
147 if (!IsRoot(child)) 196 if (!IsRoot(child))
148 { 197 {
149 // Cause the current shape to be freed and the new one to be built. 198 // Because it is a convenient time, recompute child world position and rotation based on
150 InternalRefresh(LinksetRoot); 199 // its position in the linkset.
151 ret = true; 200 RecomputeChildWorldPosition(child, true);
152 } 201 }
153 202
203 // Cannot schedule a refresh/rebuild here because this routine is called when
204 // the linkset is being rebuilt.
205 // InternalRefresh(LinksetRoot);
206
154 return ret; 207 return ret;
155 } 208 }
156 209
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 210 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
158 // this routine will restore the removed constraints. 211 // this routine will restore the removed constraints.
159 // Called at taint-time!! 212 // Called at taint-time!!
160 public override void RestoreBodyDependencies(BSPrim child) 213 public override void RestoreBodyDependencies(BSPrim child)
161 { 214 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. 215 }
216
217 // When the linkset is built, the child shape is added to the compound shape relative to the
218 // root shape. The linkset then moves around but this does not move the actual child
219 // prim. The child prim's location must be recomputed based on the location of the root shape.
220 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
221 {
222 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
223 if (lci != null)
224 {
225 if (inTaintTime)
226 {
227 OMV.Vector3 oldPos = child.RawPosition;
228 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
229 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
230 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
231 child.LocalID, oldPos, lci, child.RawPosition);
232 }
233 else
234 {
235 // TaintedObject is not used here so the raw position is set now and not at taint-time.
236 child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
237 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
238 }
239 }
240 else
241 {
242 // This happens when children have been added to the linkset but the linkset
243 // has not been constructed yet. So like, at taint time, adding children to a linkset
244 // and then changing properties of the children (makePhysical, for instance)
245 // but the post-print action of actually rebuilding the linkset has not yet happened.
246 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
247 // LogHeader, child.LocalID);
248 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
249 }
163 } 250 }
164 251
165 // ================================================================ 252 // ================================================================
@@ -181,7 +268,7 @@ public sealed class BSLinksetCompound : BSLinkset
181 } 268 }
182 269
183 // Remove the specified child from the linkset. 270 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset. 271 // Safe to call even if the child is not really in the linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child) 272 protected override void RemoveChildFromLinkset(BSPhysObject child)
186 { 273 {
187 if (m_children.Remove(child)) 274 if (m_children.Remove(child))
@@ -192,6 +279,7 @@ public sealed class BSLinksetCompound : BSLinkset
192 child.LocalID, child.PhysBody.ptr.ToString("X")); 279 child.LocalID, child.PhysBody.ptr.ToString("X"));
193 280
194 // Cause the child's body to be rebuilt and thus restored to normal operation 281 // Cause the child's body to be rebuilt and thus restored to normal operation
282 RecomputeChildWorldPosition(child, false);
195 child.ForceBodyShapeRebuild(false); 283 child.ForceBodyShapeRebuild(false);
196 284
197 if (!HasAnyChildren) 285 if (!HasAnyChildren)
@@ -215,59 +303,83 @@ public sealed class BSLinksetCompound : BSLinkset
215 // Called at taint time!! 303 // Called at taint time!!
216 private void RecomputeLinksetCompound() 304 private void RecomputeLinksetCompound()
217 { 305 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it 306 try
219 LinksetRoot.ForceBodyShapeRebuild(true);
220
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
223
224 // Add a shape for each of the other children in the linkset
225 ForEachMember(delegate(BSPhysObject cPrim)
226 { 307 {
227 if (!IsRoot(cPrim)) 308 // Suppress rebuilding while rebuilding
228 { 309 Rebuilding = true;
229 // Each child position and rotation is given relative to the root.
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
233 310
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 311 // Cause the root shape to be rebuilt as a compound object with just the root in it
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); 312 LinksetRoot.ForceBodyShapeRebuild(true);
236 313
237 if (cPrim.PhysShape.isNativeShape) 314 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
238 { 315 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
239 // Native shapes are not shared so we need to create a new one. 316
240 // A mesh or hull is created because scale is not available on a native shape. 317 // Add a shape for each of the other children in the linkset
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) 318 ForEachMember(delegate(BSPhysObject cPrim)
242 BulletShape saveShape = cPrim.PhysShape; 319 {
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape 320 if (!IsRoot(cPrim))
244 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
245 BulletShape newShape = cPrim.PhysShape;
246 cPrim.PhysShape = saveShape;
247 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot);
248 }
249 else
250 { 321 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child. 322 // Compute the displacement of the child from the root of the linkset.
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) 323 // This info is saved in the child prim so the relationship does not
324 // change over time and the new child position can be computed
325 // when the linkset is being disassembled (the linkset may have moved).
326 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
327 if (lci == null)
253 { 328 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 329 // Each child position and rotation is given relative to the root.
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 330 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
331 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
332 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
333
334 // Save relative position for recomputing child's world position after moving linkset.
335 lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
336 cPrim.LinksetInfo = lci;
337 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
256 } 338 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
258 }
259 }
260 339
261 // TODO: need to phantomize the child prims left behind. 340 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
262 // Maybe just destroy the children bodies and shapes and have them rebuild on unlink. 341 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
263 // Selection/deselection might cause way too many build/destructions esp. for LARGE linksets.
264 342
265 return false; // 'false' says to move onto the next child in the list 343 if (cPrim.PhysShape.isNativeShape)
266 }); 344 {
345 // A native shape is turning into a hull collision shape because native
346 // shapes are not shared so we have to hullify it so it will be tracked
347 // and freed at the correct time. This also solves the scaling problem
348 // (native shapes scaled but hull/meshes are assumed to not be).
349 // TODO: decide of the native shape can just be used in the compound shape.
350 // Use call to CreateGeomNonSpecial().
351 BulletShape saveShape = cPrim.PhysShape;
352 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
353 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
354 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
355 BulletShape newShape = cPrim.PhysShape;
356 cPrim.PhysShape = saveShape;
357 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot);
358 }
359 else
360 {
361 // For the shared shapes (meshes and hulls), just use the shape in the child.
362 // The reference count added here will be decremented when the compound shape
363 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
364 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
365 {
366 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
367 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
368 }
369 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot);
370 }
371 }
372 return false; // 'false' says to move onto the next child in the list
373 });
267 374
268 // With all of the linkset packed into the root prim, it has the mass of everyone. 375 // With all of the linkset packed into the root prim, it has the mass of everyone.
269 float linksetMass = LinksetMass; 376 float linksetMass = LinksetMass;
270 LinksetRoot.UpdatePhysicalMassProperties(linksetMass); 377 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
378 }
379 finally
380 {
381 Rebuilding = false;
382 }
271 383
272 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); 384 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr);
273 385
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index c855fda..732c084 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -36,9 +36,8 @@ public sealed class BSLinksetConstraints : BSLinkset
36{ 36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38 38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) 39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 { 40 {
41 base.Initialize(scene, parent);
42 } 41 }
43 42
44 // When physical properties are changed the linkset needs to recalculate 43 // When physical properties are changed the linkset needs to recalculate
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
index 390c2f9..c113a43 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
@@ -50,10 +50,11 @@ public struct MaterialAttributes
50 Avatar, 50 Avatar,
51 NumberOfTypes // the count of types in the enum. 51 NumberOfTypes // the count of types in the enum.
52 } 52 }
53
53 // Names must be in the order of the above enum. 54 // Names must be in the order of the above enum.
54 public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", 55 // These names must coorespond to the lower case field names in the MaterialAttributes
55 "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; 56 // structure as reflection is used to select the field to put the value in.
56 public static string[] MaterialAttribs = { "Density", "Friction", "Restitution"}; 57 public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
57 58
58 public MaterialAttributes(string t, float d, float f, float r) 59 public MaterialAttributes(string t, float d, float f, float r)
59 { 60 {
@@ -70,60 +71,74 @@ public struct MaterialAttributes
70 71
71public static class BSMaterials 72public static class BSMaterials
72{ 73{
73 public static MaterialAttributes[] Attributes; 74 // Attributes for each material type
75 private static readonly MaterialAttributes[] Attributes;
76
77 // Map of material name to material type code
78 public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap;
74 79
75 static BSMaterials() 80 static BSMaterials()
76 { 81 {
77 // Attribute sets for both the non-physical and physical instances of materials. 82 // Attribute sets for both the non-physical and physical instances of materials.
78 Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; 83 Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
84
85 // Map of name to type code.
86 MaterialMap = new Dictionary<string, MaterialAttributes.Material>();
87 MaterialMap.Add("Stone", MaterialAttributes.Material.Stone);
88 MaterialMap.Add("Metal", MaterialAttributes.Material.Metal);
89 MaterialMap.Add("Glass", MaterialAttributes.Material.Glass);
90 MaterialMap.Add("Wood", MaterialAttributes.Material.Wood);
91 MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh);
92 MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic);
93 MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber);
94 MaterialMap.Add("Light", MaterialAttributes.Material.Light);
95 MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar);
79 } 96 }
80 97
81 // This is where all the default material attributes are defined. 98 // This is where all the default material attributes are defined.
82 public static void InitializeFromDefaults(ConfigurationParameters parms) 99 public static void InitializeFromDefaults(ConfigurationParameters parms)
83 { 100 {
84 // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL 101 // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
85 // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", 102 float dDensity = parms.defaultDensity;
86 // "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
87 float dFriction = parms.defaultFriction; 103 float dFriction = parms.defaultFriction;
88 float dRestitution = parms.defaultRestitution; 104 float dRestitution = parms.defaultRestitution;
89 float dDensity = parms.defaultDensity;
90 Attributes[(int)MaterialAttributes.Material.Stone] = 105 Attributes[(int)MaterialAttributes.Material.Stone] =
91 new MaterialAttributes("stone",dDensity, 0.8f, 0.4f); 106 new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
92 Attributes[(int)MaterialAttributes.Material.Metal] = 107 Attributes[(int)MaterialAttributes.Material.Metal] =
93 new MaterialAttributes("metal",dDensity, 0.3f, 0.4f); 108 new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
94 Attributes[(int)MaterialAttributes.Material.Glass] = 109 Attributes[(int)MaterialAttributes.Material.Glass] =
95 new MaterialAttributes("glass",dDensity, 0.2f, 0.7f); 110 new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
96 Attributes[(int)MaterialAttributes.Material.Wood] = 111 Attributes[(int)MaterialAttributes.Material.Wood] =
97 new MaterialAttributes("wood",dDensity, 0.6f, 0.5f); 112 new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
98 Attributes[(int)MaterialAttributes.Material.Flesh] = 113 Attributes[(int)MaterialAttributes.Material.Flesh] =
99 new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f); 114 new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
100 Attributes[(int)MaterialAttributes.Material.Plastic] = 115 Attributes[(int)MaterialAttributes.Material.Plastic] =
101 new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f); 116 new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
102 Attributes[(int)MaterialAttributes.Material.Rubber] = 117 Attributes[(int)MaterialAttributes.Material.Rubber] =
103 new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f); 118 new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
104 Attributes[(int)MaterialAttributes.Material.Light] = 119 Attributes[(int)MaterialAttributes.Material.Light] =
105 new MaterialAttributes("light",dDensity, dFriction, dRestitution); 120 new MaterialAttributes("light",dDensity, dFriction, dRestitution);
106 Attributes[(int)MaterialAttributes.Material.Avatar] = 121 Attributes[(int)MaterialAttributes.Material.Avatar] =
107 new MaterialAttributes("avatar",60f, 0.2f, 0f); 122 new MaterialAttributes("avatar",60f, 0.2f, 0f);
108 123
109 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = 124 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
110 new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f); 125 new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
111 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = 126 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
112 new MaterialAttributes("metalPhysical",dDensity, 0.8f, 0.4f); 127 new MaterialAttributes("metalPhysical",dDensity, 0.8f, 0.4f);
113 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = 128 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
114 new MaterialAttributes("glassPhysical",dDensity, 0.8f, 0.7f); 129 new MaterialAttributes("glassPhysical",dDensity, 0.8f, 0.7f);
115 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = 130 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
116 new MaterialAttributes("woodPhysical",dDensity, 0.8f, 0.5f); 131 new MaterialAttributes("woodPhysical",dDensity, 0.8f, 0.5f);
117 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = 132 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
118 new MaterialAttributes("fleshPhysical",dDensity, 0.8f, 0.3f); 133 new MaterialAttributes("fleshPhysical",dDensity, 0.8f, 0.3f);
119 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = 134 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
120 new MaterialAttributes("plasticPhysical",dDensity, 0.8f, 0.7f); 135 new MaterialAttributes("plasticPhysical",dDensity, 0.8f, 0.7f);
121 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = 136 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
122 new MaterialAttributes("rubberPhysical",dDensity, 0.8f, 0.9f); 137 new MaterialAttributes("rubberPhysical",dDensity, 0.8f, 0.9f);
123 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = 138 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
124 new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution); 139 new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
125 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = 140 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
126 new MaterialAttributes("avatarPhysical",60f, 0.2f, 0f); 141 new MaterialAttributes("avatarPhysical",60f, 0.2f, 0f);
127 } 142 }
128 143
129 // Under the [BulletSim] section, one can change the individual material 144 // Under the [BulletSim] section, one can change the individual material
@@ -139,34 +154,34 @@ public static class BSMaterials
139 // the physical value. 154 // the physical value.
140 public static void InitializefromParameters(IConfig pConfig) 155 public static void InitializefromParameters(IConfig pConfig)
141 { 156 {
142 int matType = 0; 157 foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap)
143 foreach (string matName in MaterialAttributes.MaterialNames)
144 { 158 {
159 string matName = kvp.Key;
145 foreach (string attribName in MaterialAttributes.MaterialAttribs) 160 foreach (string attribName in MaterialAttributes.MaterialAttribs)
146 { 161 {
147 string paramName = matName + attribName; 162 string paramName = matName + attribName;
148 if (pConfig.Contains(paramName)) 163 if (pConfig.Contains(paramName))
149 { 164 {
150 float paramValue = pConfig.GetFloat(paramName); 165 float paramValue = pConfig.GetFloat(paramName);
151 SetAttributeValue(matType, attribName, paramValue); 166 SetAttributeValue((int)kvp.Value, attribName, paramValue);
152 // set the physical value also 167 // set the physical value also
153 SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); 168 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
154 } 169 }
155 paramName += "Physical"; 170 paramName += "Physical";
156 if (pConfig.Contains(paramName)) 171 if (pConfig.Contains(paramName))
157 { 172 {
158 float paramValue = pConfig.GetFloat(paramName); 173 float paramValue = pConfig.GetFloat(paramName);
159 SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); 174 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
160 } 175 }
161 } 176 }
162 matType++;
163 } 177 }
164 } 178 }
165 179
180 // Use reflection to set the value in the attribute structure.
166 private static void SetAttributeValue(int matType, string attribName, float val) 181 private static void SetAttributeValue(int matType, string attribName, float val)
167 { 182 {
168 MaterialAttributes thisAttrib = Attributes[matType]; 183 MaterialAttributes thisAttrib = Attributes[matType];
169 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName); 184 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
170 if (fieldInfo != null) 185 if (fieldInfo != null)
171 { 186 {
172 fieldInfo.SetValue(thisAttrib, val); 187 fieldInfo.SetValue(thisAttrib, val);
@@ -174,12 +189,12 @@ public static class BSMaterials
174 } 189 }
175 } 190 }
176 191
192 // Given a material type, return a structure of attributes.
177 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) 193 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
178 { 194 {
179 int ind = (int)type; 195 int ind = (int)type;
180 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; 196 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
181 return Attributes[ind]; 197 return Attributes[ind];
182 } 198 }
183
184} 199}
185} 200}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index 851d508..cf0a9dc 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -65,7 +65,7 @@ public abstract class BSMotor
65// Can all the incremental stepping be replaced with motor classes? 65// Can all the incremental stepping be replaced with motor classes?
66 66
67// Motor which moves CurrentValue to TargetValue over TimeScale seconds. 67// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
68// The TargetValue is decays in TargetValueDecayTimeScale and 68// The TargetValue decays in TargetValueDecayTimeScale and
69// the CurrentValue will be held back by FrictionTimeScale. 69// the CurrentValue will be held back by FrictionTimeScale.
70// TimeScale and TargetDelayTimeScale may be 'infinite' which means go decay. 70// TimeScale and TargetDelayTimeScale may be 'infinite' which means go decay.
71 71
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f6a890e..6539b43 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -60,6 +60,9 @@ public abstract class BSPhysObject : PhysicsActor
60 Linkset = BSLinkset.Factory(PhysicsScene, this); 60 Linkset = BSLinkset.Factory(PhysicsScene, this);
61 LastAssetBuildFailed = false; 61 LastAssetBuildFailed = false;
62 62
63 // Default material type
64 Material = MaterialAttributes.Material.Wood;
65
63 CollisionCollection = new CollisionEventUpdate(); 66 CollisionCollection = new CollisionEventUpdate();
64 SubscribedEventsMs = 0; 67 SubscribedEventsMs = 0;
65 CollidingStep = 0; 68 CollidingStep = 0;
@@ -72,6 +75,7 @@ public abstract class BSPhysObject : PhysicsActor
72 public string TypeName { get; protected set; } 75 public string TypeName { get; protected set; }
73 76
74 public BSLinkset Linkset { get; set; } 77 public BSLinkset Linkset { get; set; }
78 public BSLinksetInfo LinksetInfo { get; set; }
75 79
76 // Return the object mass without calculating it or having side effects 80 // Return the object mass without calculating it or having side effects
77 public abstract float RawMass { get; } 81 public abstract float RawMass { get; }
@@ -105,10 +109,17 @@ public abstract class BSPhysObject : PhysicsActor
105 public EntityProperties CurrentEntityProperties { get; set; } 109 public EntityProperties CurrentEntityProperties { get; set; }
106 public EntityProperties LastEntityProperties { get; set; } 110 public EntityProperties LastEntityProperties { get; set; }
107 111
108 public abstract OMV.Vector3 Scale { get; set; } 112 public virtual OMV.Vector3 Scale { get; set; }
109 public abstract bool IsSolid { get; } 113 public abstract bool IsSolid { get; }
110 public abstract bool IsStatic { get; } 114 public abstract bool IsStatic { get; }
111 115
116 // Materialness
117 public MaterialAttributes.Material Material { get; private set; }
118 public override void SetMaterial(int material)
119 {
120 Material = (MaterialAttributes.Material)material;
121 }
122
112 // Stop all physical motion. 123 // Stop all physical motion.
113 public abstract void ZeroMotion(bool inTaintTime); 124 public abstract void ZeroMotion(bool inTaintTime);
114 public abstract void ZeroAngularMotion(bool inTaintTime); 125 public abstract void ZeroAngularMotion(bool inTaintTime);
@@ -128,6 +139,17 @@ public abstract class BSPhysObject : PhysicsActor
128 public abstract OMV.Quaternion RawOrientation { get; set; } 139 public abstract OMV.Quaternion RawOrientation { get; set; }
129 public abstract OMV.Quaternion ForceOrientation { get; set; } 140 public abstract OMV.Quaternion ForceOrientation { get; set; }
130 141
142 // The system is telling us the velocity it wants to move at.
143 protected OMV.Vector3 m_targetVelocity;
144 public override OMV.Vector3 TargetVelocity
145 {
146 get { return m_targetVelocity; }
147 set
148 {
149 m_targetVelocity = value;
150 Velocity = value;
151 }
152 }
131 public abstract OMV.Vector3 ForceVelocity { get; set; } 153 public abstract OMV.Vector3 ForceVelocity { get; set; }
132 154
133 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 155 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
@@ -243,7 +265,9 @@ public abstract class BSPhysObject : PhysicsActor
243 SubscribedEventsMs = 0; 265 SubscribedEventsMs = 0;
244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 266 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
245 { 267 {
246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 268 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
269 if (PhysBody.HasPhysicalBody)
270 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
247 }); 271 });
248 } 272 }
249 // Return 'true' if the simulator wants collision events 273 // Return 'true' if the simulator wants collision events
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 4d203ff..c9c9c2c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -45,7 +45,6 @@ public sealed class BSPrim : BSPhysObject
45 private static readonly string LogHeader = "[BULLETS PRIM]"; 45 private static readonly string LogHeader = "[BULLETS PRIM]";
46 46
47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. 47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
48 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
49 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 48 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
50 49
51 private bool _grabbed; 50 private bool _grabbed;
@@ -93,7 +92,7 @@ public sealed class BSPrim : BSPhysObject
93 _physicsActorType = (int)ActorTypes.Prim; 92 _physicsActorType = (int)ActorTypes.Prim;
94 _position = pos; 93 _position = pos;
95 _size = size; 94 _size = size;
96 Scale = size; // the scale will be set by CreateGeom depending on object type 95 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
97 _orientation = rotation; 96 _orientation = rotation;
98 _buoyancy = 1f; 97 _buoyancy = 1f;
99 _velocity = OMV.Vector3.Zero; 98 _velocity = OMV.Vector3.Zero;
@@ -108,8 +107,8 @@ public sealed class BSPrim : BSPhysObject
108 _mass = CalculateMass(); 107 _mass = CalculateMass();
109 108
110 // No body or shape yet 109 // No body or shape yet
111 PhysBody = new BulletBody(LocalID, IntPtr.Zero); 110 PhysBody = new BulletBody(LocalID);
112 PhysShape = new BulletShape(IntPtr.Zero); 111 PhysShape = new BulletShape();
113 112
114 DetailLog("{0},BSPrim.constructor,call", LocalID); 113 DetailLog("{0},BSPrim.constructor,call", LocalID);
115 // do the actual object creation at taint time 114 // do the actual object creation at taint time
@@ -143,7 +142,9 @@ public sealed class BSPrim : BSPhysObject
143 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 142 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
144 // If there are physical body and shape, release my use of same. 143 // If there are physical body and shape, release my use of same.
145 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 144 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
145 PhysBody.Clear();
146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
147 PhysShape.Clear();
147 }); 148 });
148 } 149 }
149 150
@@ -157,12 +158,10 @@ public sealed class BSPrim : BSPhysObject
157 // We presume the scale and size are the same. If scale must be changed for 158 // We presume the scale and size are the same. If scale must be changed for
158 // the physical shape, that is done when the geometry is built. 159 // the physical shape, that is done when the geometry is built.
159 _size = value; 160 _size = value;
161 Scale = _size;
160 ForceBodyShapeRebuild(false); 162 ForceBodyShapeRebuild(false);
161 } 163 }
162 } 164 }
163 // Scale is what we set in the physics engine. It is different than 'size' in that
164 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
165 public override OMV.Vector3 Scale { get; set; }
166 165
167 public override PrimitiveBaseShape Shape { 166 public override PrimitiveBaseShape Shape {
168 set { 167 set {
@@ -189,7 +188,8 @@ public sealed class BSPrim : BSPhysObject
189 } 188 }
190 } 189 }
191 public override bool Selected { 190 public override bool Selected {
192 set { 191 set
192 {
193 if (value != _isSelected) 193 if (value != _isSelected)
194 { 194 {
195 _isSelected = value; 195 _isSelected = value;
@@ -247,7 +247,8 @@ public sealed class BSPrim : BSPhysObject
247 // Zero some other properties in the physics engine 247 // Zero some other properties in the physics engine
248 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 248 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
249 { 249 {
250 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 250 if (PhysBody.HasPhysicalBody)
251 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
251 }); 252 });
252 } 253 }
253 public override void ZeroAngularMotion(bool inTaintTime) 254 public override void ZeroAngularMotion(bool inTaintTime)
@@ -257,8 +258,11 @@ public sealed class BSPrim : BSPhysObject
257 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 258 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
258 { 259 {
259 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); 260 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
260 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 261 if (PhysBody.HasPhysicalBody)
261 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 262 {
263 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
264 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
265 }
262 }); 266 });
263 } 267 }
264 268
@@ -295,8 +299,11 @@ public sealed class BSPrim : BSPhysObject
295 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 299 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
296 { 300 {
297 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 301 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
298 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 302 if (PhysBody.HasPhysicalBody)
299 ActivateIfPhysical(false); 303 {
304 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
305 ActivateIfPhysical(false);
306 }
300 }); 307 });
301 } 308 }
302 } 309 }
@@ -322,12 +329,12 @@ public sealed class BSPrim : BSPhysObject
322 329
323 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 330 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
324 OMV.Vector3 upForce = OMV.Vector3.Zero; 331 OMV.Vector3 upForce = OMV.Vector3.Zero;
325 if (Position.Z < terrainHeight) 332 if (RawPosition.Z < terrainHeight)
326 { 333 {
327 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 334 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
328 float targetHeight = terrainHeight + (Size.Z / 2f); 335 float targetHeight = terrainHeight + (Size.Z / 2f);
329 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. 336 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
330 upForce.Z = (terrainHeight - Position.Z) * 1f; 337 upForce.Z = (terrainHeight - RawPosition.Z) * 1f;
331 ret = true; 338 ret = true;
332 } 339 }
333 340
@@ -335,10 +342,10 @@ public sealed class BSPrim : BSPhysObject
335 { 342 {
336 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 343 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
337 // TODO: a floating motor so object will bob in the water 344 // TODO: a floating motor so object will bob in the water
338 if (Math.Abs(Position.Z - waterHeight) > 0.1f) 345 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
339 { 346 {
340 // Upforce proportional to the distance away from the water. Correct the error in 1 sec. 347 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
341 upForce.Z = (waterHeight - Position.Z) * 1f; 348 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
342 ret = true; 349 ret = true;
343 } 350 }
344 } 351 }
@@ -413,7 +420,8 @@ public sealed class BSPrim : BSPhysObject
413 PhysicsScene.TaintedObject("BSPrim.setForce", delegate() 420 PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
414 { 421 {
415 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 422 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
416 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 423 if (PhysBody.HasPhysicalBody)
424 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
417 }); 425 });
418 } 426 }
419 } 427 }
@@ -507,7 +515,8 @@ public sealed class BSPrim : BSPhysObject
507 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 515 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
508 { 516 {
509 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 517 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
510 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 518 if (PhysBody.HasPhysicalBody)
519 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
511 }); 520 });
512 } 521 }
513 } 522 }
@@ -556,9 +565,12 @@ public sealed class BSPrim : BSPhysObject
556 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 565 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
557 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 566 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
558 { 567 {
559 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 568 if (PhysBody.HasPhysicalBody)
560 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 569 {
561 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 570 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
571 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
572 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
573 }
562 }); 574 });
563 } 575 }
564 } 576 }
@@ -649,14 +661,7 @@ public sealed class BSPrim : BSPhysObject
649 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 661 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
650 662
651 // Collision filter can be set only when the object is in the world 663 // Collision filter can be set only when the object is in the world
652 if (PhysBody.collisionGroup != 0 || PhysBody.collisionMask != 0) 664 PhysBody.ApplyCollisionMask();
653 {
654 if (!BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr, (uint)PhysBody.collisionGroup, (uint)PhysBody.collisionMask))
655 {
656 PhysicsScene.Logger.ErrorFormat("{0} Failure setting prim collision mask. localID={1}, grp={2:X}, mask={3:X}",
657 LogHeader, LocalID, PhysBody.collisionGroup, PhysBody.collisionMask);
658 }
659 }
660 665
661 // Recompute any linkset parameters. 666 // Recompute any linkset parameters.
662 // When going from non-physical to physical, this re-enables the constraints that 667 // When going from non-physical to physical, this re-enables the constraints that
@@ -683,8 +688,9 @@ public sealed class BSPrim : BSPhysObject
683 ZeroMotion(true); 688 ZeroMotion(true);
684 689
685 // Set various physical properties so other object interact properly 690 // Set various physical properties so other object interact properly
686 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); 691 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
687 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); 692 BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
693 BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
688 694
689 // Mass is zero which disables a bunch of physics stuff in Bullet 695 // Mass is zero which disables a bunch of physics stuff in Bullet
690 UpdatePhysicalMassProperties(0f); 696 UpdatePhysicalMassProperties(0f);
@@ -700,20 +706,21 @@ public sealed class BSPrim : BSPhysObject
700 // Start it out sleeping and physical actions could wake it up. 706 // Start it out sleeping and physical actions could wake it up.
701 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING); 707 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING);
702 708
709 // This collides like a static object
710 PhysBody.collisionType = CollisionType.Static;
711
703 // There can be special things needed for implementing linksets 712 // There can be special things needed for implementing linksets
704 Linkset.MakeStatic(this); 713 Linkset.MakeStatic(this);
705
706 PhysBody.collisionGroup = CollisionFilterGroups.StaticObjectGroup;
707 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
708 } 714 }
709 else 715 else
710 { 716 {
711 // Not a Bullet static object 717 // Not a Bullet static object
712 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 718 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
713 719
714 // Set various physical properties so internal dynamic properties will get computed correctly as they are set 720 // Set various physical properties so other object interact properly
715 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); 721 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
716 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); 722 BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
723 BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
717 724
718 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 725 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
719 // Since this can be called multiple times, only zero forces when becoming physical 726 // Since this can be called multiple times, only zero forces when becoming physical
@@ -741,16 +748,15 @@ public sealed class BSPrim : BSPhysObject
741 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); 748 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
742 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 749 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
743 750
744 // There might be special things needed for implementing linksets. 751 // This collides like an object.
745 Linkset.MakeDynamic(this); 752 PhysBody.collisionType = CollisionType.Dynamic;
746 753
747 // Force activation of the object so Bullet will act on it. 754 // Force activation of the object so Bullet will act on it.
748 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 755 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
749 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); 756 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
750 // BulletSimAPI.Activate2(BSBody.ptr, true);
751 757
752 PhysBody.collisionGroup = CollisionFilterGroups.ObjectGroup; 758 // There might be special things needed for implementing linksets.
753 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; 759 Linkset.MakeDynamic(this);
754 } 760 }
755 } 761 }
756 762
@@ -777,8 +783,9 @@ public sealed class BSPrim : BSPhysObject
777 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 783 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
778 } 784 }
779 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 785 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
780 PhysBody.collisionGroup = CollisionFilterGroups.VolumeDetectGroup; 786
781 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; 787 // Change collision info from a static object to a ghosty collision object
788 PhysBody.collisionType = CollisionType.VolumeDetect;
782 } 789 }
783 } 790 }
784 791
@@ -861,7 +868,8 @@ public sealed class BSPrim : BSPhysObject
861 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 868 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
862 { 869 {
863 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 870 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
864 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 871 if (PhysBody.HasPhysicalBody)
872 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
865 }); 873 });
866 } 874 }
867 } 875 }
@@ -896,8 +904,11 @@ public sealed class BSPrim : BSPhysObject
896 _buoyancy = value; 904 _buoyancy = value;
897 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 905 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
898 // Buoyancy is faked by changing the gravity applied to the object 906 // Buoyancy is faked by changing the gravity applied to the object
899 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 907 if (PhysBody.HasPhysicalBody)
900 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 908 {
909 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
910 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
911 }
901 } 912 }
902 } 913 }
903 914
@@ -965,7 +976,8 @@ public sealed class BSPrim : BSPhysObject
965 } 976 }
966 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); 977 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum);
967 if (fSum != OMV.Vector3.Zero) 978 if (fSum != OMV.Vector3.Zero)
968 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); 979 if (PhysBody.HasPhysicalBody)
980 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
969 }); 981 });
970 } 982 }
971 983
@@ -976,7 +988,8 @@ public sealed class BSPrim : BSPhysObject
976 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate() 988 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
977 { 989 {
978 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); 990 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse);
979 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); 991 if (PhysBody.HasPhysicalBody)
992 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse);
980 }); 993 });
981 } 994 }
982 995
@@ -1012,7 +1025,8 @@ public sealed class BSPrim : BSPhysObject
1012 DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum); 1025 DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
1013 if (fSum != OMV.Vector3.Zero) 1026 if (fSum != OMV.Vector3.Zero)
1014 { 1027 {
1015 BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); 1028 if (PhysBody.HasPhysicalBody)
1029 BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
1016 _torque = fSum; 1030 _torque = fSum;
1017 } 1031 }
1018 }); 1032 });
@@ -1026,7 +1040,8 @@ public sealed class BSPrim : BSPhysObject
1026 OMV.Vector3 applyImpulse = impulse; 1040 OMV.Vector3 applyImpulse = impulse;
1027 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1041 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1028 { 1042 {
1029 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); 1043 if (PhysBody.HasPhysicalBody)
1044 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
1030 }); 1045 });
1031 } 1046 }
1032 1047
@@ -1344,7 +1359,6 @@ public sealed class BSPrim : BSPhysObject
1344 // Create the correct physical representation for this type of object. 1359 // Create the correct physical representation for this type of object.
1345 // Updates PhysBody and PhysShape with the new information. 1360 // Updates PhysBody and PhysShape with the new information.
1346 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1361 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1347 // Returns 'true' if either the body or the shape was changed.
1348 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) 1362 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1349 { 1363 {
1350 // Called if the current prim body is about to be destroyed. 1364 // Called if the current prim body is about to be destroyed.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index f72bd74..cf5bb57 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -188,6 +188,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
188 private bool m_physicsLoggingDoFlush; 188 private bool m_physicsLoggingDoFlush;
189 // 'true' of the vehicle code is to log lots of details 189 // 'true' of the vehicle code is to log lots of details
190 public bool VehicleLoggingEnabled { get; private set; } 190 public bool VehicleLoggingEnabled { get; private set; }
191 public bool VehiclePhysicalLoggingEnabled { get; private set; }
192 public bool VehicleScaleAngularVelocityByTimestep { get; private set; }
191 193
192 #region Construction and Initialization 194 #region Construction and Initialization
193 public BSScene(string identifier) 195 public BSScene(string identifier)
@@ -297,6 +299,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
297 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); 299 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
298 // Very detailed logging for vehicle debugging 300 // Very detailed logging for vehicle debugging
299 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 301 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
302 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
300 303
301 // Do any replacements in the parameters 304 // Do any replacements in the parameters
302 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 305 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
@@ -306,6 +309,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
306 BSMaterials.InitializeFromDefaults(Params); 309 BSMaterials.InitializeFromDefaults(Params);
307 if (pConfig != null) 310 if (pConfig != null)
308 { 311 {
312 // Let the user add new and interesting material property values.
309 BSMaterials.InitializefromParameters(pConfig); 313 BSMaterials.InitializefromParameters(pConfig);
310 } 314 }
311 } 315 }
@@ -501,7 +505,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
501 505
502 try 506 try
503 { 507 {
504 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 508 if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG
505 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); 509 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
506 510
507 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, 511 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
@@ -510,7 +514,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
510 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 514 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
511 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", 515 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
512 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); 516 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
513 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 517 if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG
514 } 518 }
515 catch (Exception e) 519 catch (Exception e)
516 { 520 {
@@ -1226,6 +1230,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1226 (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); }, 1230 (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); },
1227 (s) => { return s.m_params[0].vehicleAngularDamping; }, 1231 (s) => { return s.m_params[0].vehicleAngularDamping; },
1228 (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ), 1232 (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ),
1233 new ParameterDefn("VehicleScaleAngularVelocityByTimestep", "If true, scale angular turning by timestep",
1234 ConfigurationParameters.numericFalse,
1235 (s,cf,p,v) => { s.VehicleScaleAngularVelocityByTimestep = cf.GetBoolean(p, s.BoolNumeric(v)); },
1236 (s) => { return s.NumericBool(s.VehicleScaleAngularVelocityByTimestep); },
1237 (s,p,l,v) => { s.VehicleScaleAngularVelocityByTimestep = s.BoolNumeric(v); } ),
1229 1238
1230 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 1239 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1231 0f, 1240 0f,
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index a77dee9..d6e2fe9 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -126,6 +126,11 @@ public sealed class BSShapeCollection : IDisposable
126 return ret; 126 return ret;
127 } 127 }
128 128
129 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim)
130 {
131 return GetBodyAndShape(forceRebuild, sim, prim, null, null);
132 }
133
129 // Track another user of a body. 134 // Track another user of a body.
130 // We presume the caller has allocated the body. 135 // We presume the caller has allocated the body.
131 // Bodies only have one user so the body is just put into the world if not already there. 136 // Bodies only have one user so the body is just put into the world if not already there.
@@ -149,7 +154,7 @@ public sealed class BSShapeCollection : IDisposable
149 // Called when releasing use of a BSBody. BSShape is handled separately. 154 // Called when releasing use of a BSBody. BSShape is handled separately.
150 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) 155 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
151 { 156 {
152 if (body.ptr == IntPtr.Zero) 157 if (!body.HasPhysicalBody)
153 return; 158 return;
154 159
155 lock (m_collectionActivityLock) 160 lock (m_collectionActivityLock)
@@ -243,12 +248,12 @@ public sealed class BSShapeCollection : IDisposable
243 // Release the usage of a shape. 248 // Release the usage of a shape.
244 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) 249 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
245 { 250 {
246 if (shape.ptr == IntPtr.Zero) 251 if (!shape.HasPhysicalShape)
247 return; 252 return;
248 253
249 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() 254 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
250 { 255 {
251 if (shape.ptr != IntPtr.Zero) 256 if (shape.HasPhysicalShape)
252 { 257 {
253 if (shape.isNativeShape) 258 if (shape.isNativeShape)
254 { 259 {
@@ -440,7 +445,7 @@ public sealed class BSShapeCollection : IDisposable
440 } 445 }
441 446
442 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. 447 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
443 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 448 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
444 { 449 {
445 bool ret = false; 450 bool ret = false;
446 bool haveShape = false; 451 bool haveShape = false;
@@ -460,6 +465,11 @@ public sealed class BSShapeCollection : IDisposable
460 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 465 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
461 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 466 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
462 { 467 {
468 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
469 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
470 if (prim.PhysShape.HasPhysicalShape)
471 scaleOfExistingShape = BulletSimAPI.GetLocalScaling2(prim.PhysShape.ptr);
472
463 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", 473 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
464 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); 474 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
465 475
@@ -469,7 +479,7 @@ public sealed class BSShapeCollection : IDisposable
469 { 479 {
470 haveShape = true; 480 haveShape = true;
471 if (forceRebuild 481 if (forceRebuild
472 || prim.Scale != prim.Size 482 || prim.Scale != scaleOfExistingShape
473 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 483 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
474 ) 484 )
475 { 485 {
@@ -483,7 +493,7 @@ public sealed class BSShapeCollection : IDisposable
483 { 493 {
484 haveShape = true; 494 haveShape = true;
485 if (forceRebuild 495 if (forceRebuild
486 || prim.Scale != prim.Size 496 || prim.Scale != scaleOfExistingShape
487 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 497 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
488 ) 498 )
489 { 499 {
@@ -542,7 +552,6 @@ public sealed class BSShapeCollection : IDisposable
542 prim.LocalID, newShape, prim.Scale); 552 prim.LocalID, newShape, prim.Scale);
543 553
544 // native shapes are scaled by Bullet 554 // native shapes are scaled by Bullet
545 prim.Scale = prim.Size;
546 prim.PhysShape = newShape; 555 prim.PhysShape = newShape;
547 return true; 556 return true;
548 } 557 }
@@ -555,8 +564,8 @@ public sealed class BSShapeCollection : IDisposable
555 ShapeData nativeShapeData = new ShapeData(); 564 ShapeData nativeShapeData = new ShapeData();
556 nativeShapeData.Type = shapeType; 565 nativeShapeData.Type = shapeType;
557 nativeShapeData.ID = prim.LocalID; 566 nativeShapeData.ID = prim.LocalID;
558 nativeShapeData.Scale = prim.Size; 567 nativeShapeData.Scale = prim.Scale;
559 nativeShapeData.Size = prim.Size; // unneeded, I think. 568 nativeShapeData.Size = prim.Scale; // unneeded, I think.
560 nativeShapeData.MeshKey = (ulong)shapeKey; 569 nativeShapeData.MeshKey = (ulong)shapeKey;
561 nativeShapeData.HullKey = (ulong)shapeKey; 570 nativeShapeData.HullKey = (ulong)shapeKey;
562 571
@@ -573,7 +582,7 @@ public sealed class BSShapeCollection : IDisposable
573 // Native shapes are scaled in Bullet so set the scaling to the size 582 // Native shapes are scaled in Bullet so set the scaling to the size
574 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); 583 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
575 } 584 }
576 if (newShape.ptr == IntPtr.Zero) 585 if (!newShape.HasPhysicalShape)
577 { 586 {
578 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 587 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
579 LogHeader, prim.LocalID, shapeType); 588 LogHeader, prim.LocalID, shapeType);
@@ -590,7 +599,7 @@ public sealed class BSShapeCollection : IDisposable
590 // Called at taint-time! 599 // Called at taint-time!
591 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 600 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
592 { 601 {
593 BulletShape newShape = new BulletShape(IntPtr.Zero); 602 BulletShape newShape = new BulletShape();
594 603
595 float lod; 604 float lod;
596 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 605 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
@@ -611,8 +620,6 @@ public sealed class BSShapeCollection : IDisposable
611 620
612 ReferenceShape(newShape); 621 ReferenceShape(newShape);
613 622
614 // meshes are already scaled by the meshmerizer
615 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
616 prim.PhysShape = newShape; 623 prim.PhysShape = newShape;
617 624
618 return true; // 'true' means a new shape has been added to this prim 625 return true; // 'true' means a new shape has been added to this prim
@@ -683,8 +690,6 @@ public sealed class BSShapeCollection : IDisposable
683 690
684 ReferenceShape(newShape); 691 ReferenceShape(newShape);
685 692
686 // hulls are already scaled by the meshmerizer
687 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
688 prim.PhysShape = newShape; 693 prim.PhysShape = newShape;
689 return true; // 'true' means a new shape has been added to this prim 694 return true; // 'true' means a new shape has been added to this prim
690 } 695 }
@@ -793,7 +798,7 @@ public sealed class BSShapeCollection : IDisposable
793 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL); 798 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
794 newShape.shapeKey = newHullKey; 799 newShape.shapeKey = newHullKey;
795 800
796 return newShape; // 'true' means a new shape has been added to this prim 801 return newShape;
797 } 802 }
798 803
799 // Callback from convex hull creater with a newly created hull. 804 // Callback from convex hull creater with a newly created hull.
@@ -860,7 +865,7 @@ public sealed class BSShapeCollection : IDisposable
860 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) 865 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
861 { 866 {
862 // If the shape was successfully created, nothing more to do 867 // If the shape was successfully created, nothing more to do
863 if (newShape.ptr != IntPtr.Zero) 868 if (newShape.HasPhysicalShape)
864 return newShape; 869 return newShape;
865 870
866 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 871 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
@@ -919,7 +924,7 @@ public sealed class BSShapeCollection : IDisposable
919 bool ret = false; 924 bool ret = false;
920 925
921 // the mesh, hull or native shape must have already been created in Bullet 926 // the mesh, hull or native shape must have already been created in Bullet
922 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); 927 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
923 928
924 // If there is an existing body, verify it's of an acceptable type. 929 // If there is an existing body, verify it's of an acceptable type.
925 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 930 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
index 83b9c37..2b120d6 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -121,9 +121,8 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
121 // redo its bounding box now that it is in the world 121 // redo its bounding box now that it is in the world
122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
123 123
124 BulletSimAPI.SetCollisionGroupMask2(m_mapInfo.terrainBody.ptr, 124 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
125 (uint)CollisionFilterGroups.TerrainGroup, 125 m_mapInfo.terrainBody.ApplyCollisionMask();
126 (uint)CollisionFilterGroups.TerrainMask);
127 126
128 // Make it so the terrain will not move or be considered for movement. 127 // Make it so the terrain will not move or be considered for movement.
129 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 128 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
@@ -136,7 +135,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
136 { 135 {
137 if (m_mapInfo != null) 136 if (m_mapInfo != null)
138 { 137 {
139 if (m_mapInfo.terrainBody.ptr != IntPtr.Zero) 138 if (m_mapInfo.terrainBody.HasPhysicalBody)
140 { 139 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 140 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
142 // Frees both the body and the shape. 141 // Frees both the body and the shape.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 83df360..5dbd8ce 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -140,8 +140,8 @@ public sealed class BSTerrainManager
140 // Ground plane does not move 140 // Ground plane does not move
141 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); 141 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
142 // Everything collides with the ground plane. 142 // Everything collides with the ground plane.
143 BulletSimAPI.SetCollisionGroupMask2(m_groundPlane.ptr, 143 m_groundPlane.collisionType = CollisionType.Groundplane;
144 (uint)CollisionFilterGroups.GroundPlaneGroup, (uint)CollisionFilterGroups.GroundPlaneMask); 144 m_groundPlane.ApplyCollisionMask();
145 145
146 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 146 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
147 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 147 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
@@ -151,13 +151,13 @@ public sealed class BSTerrainManager
151 // Release all the terrain structures we might have allocated 151 // Release all the terrain structures we might have allocated
152 public void ReleaseGroundPlaneAndTerrain() 152 public void ReleaseGroundPlaneAndTerrain()
153 { 153 {
154 if (m_groundPlane.ptr != IntPtr.Zero) 154 if (m_groundPlane.HasPhysicalBody)
155 { 155 {
156 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) 156 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
157 { 157 {
158 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); 158 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
159 } 159 }
160 m_groundPlane.ptr = IntPtr.Zero; 160 m_groundPlane.Clear();
161 } 161 }
162 162
163 ReleaseTerrain(); 163 ReleaseTerrain();
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index 6ce767d..6dc0d92 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -94,7 +94,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
94 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 94 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
95 indicesCount, indices, verticesCount, vertices), 95 indicesCount, indices, verticesCount, vertices),
96 BSPhysicsShapeType.SHAPE_MESH); 96 BSPhysicsShapeType.SHAPE_MESH);
97 if (m_terrainShape.ptr == IntPtr.Zero) 97 if (!m_terrainShape.HasPhysicalShape)
98 { 98 {
99 // DISASTER!! 99 // DISASTER!!
100 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); 100 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
@@ -107,7 +107,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
107 Quaternion rot = Quaternion.Identity; 107 Quaternion rot = Quaternion.Identity;
108 108
109 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); 109 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot));
110 if (m_terrainBody.ptr == IntPtr.Zero) 110 if (!m_terrainBody.HasPhysicalBody)
111 { 111 {
112 // DISASTER!! 112 // DISASTER!!
113 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); 113 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
@@ -130,9 +130,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
130 // Redo its bounding box now that it is in the world 130 // Redo its bounding box now that it is in the world
131 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); 131 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
132 132
133 BulletSimAPI.SetCollisionGroupMask2(m_terrainBody.ptr, 133 m_terrainBody.collisionType = CollisionType.Terrain;
134 (uint)CollisionFilterGroups.TerrainGroup, 134 m_terrainBody.ApplyCollisionMask();
135 (uint)CollisionFilterGroups.TerrainMask);
136 135
137 // Make it so the terrain will not move or be considered for movement. 136 // Make it so the terrain will not move or be considered for movement.
138 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 137 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
@@ -140,7 +139,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
140 139
141 public override void Dispose() 140 public override void Dispose()
142 { 141 {
143 if (m_terrainBody.ptr != IntPtr.Zero) 142 if (m_terrainBody.HasPhysicalBody)
144 { 143 {
145 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 144 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
146 // Frees both the body and the shape. 145 // Frees both the body and the shape.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 2671995..962b540 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -25,6 +25,7 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic;
28using System.Runtime.InteropServices; 29using System.Runtime.InteropServices;
29using System.Security; 30using System.Security;
30using System.Text; 31using System.Text;
@@ -32,93 +33,6 @@ using OpenMetaverse;
32 33
33namespace OpenSim.Region.Physics.BulletSPlugin { 34namespace OpenSim.Region.Physics.BulletSPlugin {
34 35
35// Classes to allow some type checking for the API
36// These hold pointers to allocated objects in the unmanaged space.
37
38// The physics engine controller class created at initialization
39public struct BulletSim
40{
41 public BulletSim(uint worldId, BSScene bss, IntPtr xx)
42 {
43 ptr = xx;
44 worldID = worldId;
45 physicsScene = bss;
46 }
47 public IntPtr ptr;
48 public uint worldID;
49 // The scene is only in here so very low level routines have a handle to print debug/error messages
50 public BSScene physicsScene;
51}
52
53// An allocated Bullet btRigidBody
54public struct BulletBody
55{
56 public BulletBody(uint id, IntPtr xx)
57 {
58 ID = id;
59 ptr = xx;
60 collisionGroup = 0;
61 collisionMask = 0;
62 }
63 public IntPtr ptr;
64 public uint ID;
65 public CollisionFilterGroups collisionGroup;
66 public CollisionFilterGroups collisionMask;
67 public override string ToString()
68 {
69 StringBuilder buff = new StringBuilder();
70 buff.Append("<id=");
71 buff.Append(ID.ToString());
72 buff.Append(",p=");
73 buff.Append(ptr.ToString("X"));
74 if (collisionGroup != 0 || collisionMask != 0)
75 {
76 buff.Append(",g=");
77 buff.Append(collisionGroup.ToString("X"));
78 buff.Append(",m=");
79 buff.Append(collisionMask.ToString("X"));
80 }
81 buff.Append(">");
82 return buff.ToString();
83 }
84}
85
86public struct BulletShape
87{
88 public BulletShape(IntPtr xx)
89 {
90 ptr = xx;
91 type=BSPhysicsShapeType.SHAPE_UNKNOWN;
92 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
93 isNativeShape = false;
94 }
95 public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
96 {
97 ptr = xx;
98 type = typ;
99 shapeKey = 0;
100 isNativeShape = false;
101 }
102 public IntPtr ptr;
103 public BSPhysicsShapeType type;
104 public System.UInt64 shapeKey;
105 public bool isNativeShape;
106 public override string ToString()
107 {
108 StringBuilder buff = new StringBuilder();
109 buff.Append("<p=");
110 buff.Append(ptr.ToString("X"));
111 buff.Append(",s=");
112 buff.Append(type.ToString());
113 buff.Append(",k=");
114 buff.Append(shapeKey.ToString("X"));
115 buff.Append(",n=");
116 buff.Append(isNativeShape.ToString());
117 buff.Append(">");
118 return buff.ToString();
119 }
120}
121
122 // Constraint type values as defined by Bullet 36 // Constraint type values as defined by Bullet
123public enum ConstraintType : int 37public enum ConstraintType : int
124{ 38{
@@ -132,44 +46,6 @@ public enum ConstraintType : int
132 MAX_CONSTRAINT_TYPE 46 MAX_CONSTRAINT_TYPE
133} 47}
134 48
135// An allocated Bullet btConstraint
136public struct BulletConstraint
137{
138 public BulletConstraint(IntPtr xx)
139 {
140 ptr = xx;
141 }
142 public IntPtr ptr;
143}
144
145// An allocated HeightMapThing which holds various heightmap info.
146// Made a class rather than a struct so there would be only one
147// instance of this and C# will pass around pointers rather
148// than making copies.
149public class BulletHeightMapInfo
150{
151 public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
152 ID = id;
153 Ptr = xx;
154 heightMap = hm;
155 terrainRegionBase = Vector3.Zero;
156 minCoords = new Vector3(100f, 100f, 25f);
157 maxCoords = new Vector3(101f, 101f, 26f);
158 minZ = maxZ = 0f;
159 sizeX = sizeY = 256f;
160 }
161 public uint ID;
162 public IntPtr Ptr;
163 public float[] heightMap;
164 public Vector3 terrainRegionBase;
165 public Vector3 minCoords;
166 public Vector3 maxCoords;
167 public float sizeX, sizeY;
168 public float minZ, maxZ;
169 public BulletShape terrainShape;
170 public BulletBody terrainBody;
171}
172
173// =============================================================================== 49// ===============================================================================
174[StructLayout(LayoutKind.Sequential)] 50[StructLayout(LayoutKind.Sequential)]
175public struct ConvexHull 51public struct ConvexHull
@@ -362,21 +238,15 @@ public enum CollisionFlags : uint
362 BS_FLOATS_ON_WATER = 1 << 11, 238 BS_FLOATS_ON_WATER = 1 << 11,
363 BS_VEHICLE_COLLISIONS = 1 << 12, 239 BS_VEHICLE_COLLISIONS = 1 << 12,
364 BS_NONE = 0, 240 BS_NONE = 0,
365 BS_ALL = 0xFFFFFFFF, 241 BS_ALL = 0xFFFFFFFF
366
367 // These are the collision flags switched depending on physical state.
368 // The other flags are used for other things and should not be fooled with.
369 BS_ACTIVE = CF_STATIC_OBJECT
370 | CF_KINEMATIC_OBJECT
371 | CF_NO_CONTACT_RESPONSE
372}; 242};
373 243
374// Values for collisions groups and masks 244// Values f collisions groups and masks
375public enum CollisionFilterGroups : uint 245public enum CollisionFilterGroups : uint
376{ 246{
377 // Don't use the bit definitions!! Define the use in a 247 // Don't use the bit definitions!! Define the use in a
378 // filter/mask definition below. This way collision interactions 248 // filter/mask definition below. This way collision interactions
379 // are more easily debugged. 249 // are more easily found and debugged.
380 BNoneGroup = 0, 250 BNoneGroup = 0,
381 BDefaultGroup = 1 << 0, 251 BDefaultGroup = 1 << 0,
382 BStaticGroup = 1 << 1, 252 BStaticGroup = 1 << 1,
@@ -390,24 +260,8 @@ public enum CollisionFilterGroups : uint
390 BTerrainGroup = 1 << 11, 260 BTerrainGroup = 1 << 11,
391 BRaycastGroup = 1 << 12, 261 BRaycastGroup = 1 << 12,
392 BSolidGroup = 1 << 13, 262 BSolidGroup = 1 << 13,
393 BLinksetGroup = 1 << 14, 263 // BLinksetGroup = xx // a linkset proper is either static or dynamic
394 264 BLinksetChildGroup = 1 << 14,
395 // The collsion filters and masked are defined in one place -- don't want them scattered
396 AvatarGroup = BCharacterGroup,
397 AvatarMask = BAllGroup,
398 ObjectGroup = BSolidGroup,
399 ObjectMask = BAllGroup,
400 StaticObjectGroup = BStaticGroup,
401 StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
402 LinksetGroup = BLinksetGroup,
403 LinksetMask = BAllGroup & ~BLinksetGroup, // linkset objects don't collide with each other
404 VolumeDetectGroup = BSensorTrigger,
405 VolumeDetectMask = ~BSensorTrigger,
406 TerrainGroup = BTerrainGroup,
407 TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
408 GroundPlaneGroup = BGroundPlaneGroup,
409 GroundPlaneMask = BAllGroup
410
411}; 265};
412 266
413// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 267// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
@@ -434,7 +288,7 @@ public enum ConstraintParamAxis : int
434 288
435// =============================================================================== 289// ===============================================================================
436static class BulletSimAPI { 290static class BulletSimAPI {
437 291// ===============================================================================
438// Link back to the managed code for outputting log messages 292// Link back to the managed code for outputting log messages
439[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 293[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
440public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); 294public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
new file mode 100755
index 0000000..662177f
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
@@ -0,0 +1,278 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OMV = OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34// Classes to allow some type checking for the API
35// These hold pointers to allocated objects in the unmanaged space.
36
37// The physics engine controller class created at initialization
38public struct BulletSim
39{
40 public BulletSim(uint worldId, BSScene bss, IntPtr xx)
41 {
42 ptr = xx;
43 worldID = worldId;
44 physicsScene = bss;
45 }
46 public IntPtr ptr;
47 public uint worldID;
48 // The scene is only in here so very low level routines have a handle to print debug/error messages
49 public BSScene physicsScene;
50}
51
52// An allocated Bullet btRigidBody
53public struct BulletBody
54{
55 public BulletBody(uint id) : this(id, IntPtr.Zero)
56 {
57 }
58 public BulletBody(uint id, IntPtr xx)
59 {
60 ID = id;
61 ptr = xx;
62 collisionType = CollisionType.Static;
63 }
64 public IntPtr ptr;
65 public uint ID;
66 public CollisionType collisionType;
67
68 public void Clear()
69 {
70 ptr = IntPtr.Zero;
71 }
72 public bool HasPhysicalBody { get { return ptr != IntPtr.Zero; } }
73
74 // Apply the specificed collision mask into the physical world
75 public void ApplyCollisionMask()
76 {
77 // Should assert the body has been added to the physical world.
78 // (The collision masks are stored in the collision proxy cache which only exists for
79 // a collision body that is in the world.)
80 BulletSimAPI.SetCollisionGroupMask2(ptr,
81 BulletSimData.CollisionTypeMasks[collisionType].group,
82 BulletSimData.CollisionTypeMasks[collisionType].mask);
83 }
84
85 public override string ToString()
86 {
87 StringBuilder buff = new StringBuilder();
88 buff.Append("<id=");
89 buff.Append(ID.ToString());
90 buff.Append(",p=");
91 buff.Append(ptr.ToString("X"));
92 buff.Append(",c=");
93 buff.Append(collisionType);
94 buff.Append(">");
95 return buff.ToString();
96 }
97}
98
99public struct BulletShape
100{
101 public BulletShape(IntPtr xx) : this(xx, BSPhysicsShapeType.SHAPE_UNKNOWN)
102 {
103 }
104 public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
105 {
106 ptr = xx;
107 type = typ;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false;
110 }
111 public IntPtr ptr;
112 public BSPhysicsShapeType type;
113 public System.UInt64 shapeKey;
114 public bool isNativeShape;
115
116 public void Clear()
117 {
118 ptr = IntPtr.Zero;
119 }
120 public bool HasPhysicalShape { get { return ptr != IntPtr.Zero; } }
121
122 public override string ToString()
123 {
124 StringBuilder buff = new StringBuilder();
125 buff.Append("<p=");
126 buff.Append(ptr.ToString("X"));
127 buff.Append(",s=");
128 buff.Append(type.ToString());
129 buff.Append(",k=");
130 buff.Append(shapeKey.ToString("X"));
131 buff.Append(",n=");
132 buff.Append(isNativeShape.ToString());
133 buff.Append(">");
134 return buff.ToString();
135 }
136}
137
138// An allocated Bullet btConstraint
139public struct BulletConstraint
140{
141 public BulletConstraint(IntPtr xx)
142 {
143 ptr = xx;
144 }
145 public IntPtr ptr;
146
147 public void Clear()
148 {
149 ptr = IntPtr.Zero;
150 }
151 public bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } }
152}
153
154// An allocated HeightMapThing which holds various heightmap info.
155// Made a class rather than a struct so there would be only one
156// instance of this and C# will pass around pointers rather
157// than making copies.
158public class BulletHeightMapInfo
159{
160 public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
161 ID = id;
162 Ptr = xx;
163 heightMap = hm;
164 terrainRegionBase = OMV.Vector3.Zero;
165 minCoords = new OMV.Vector3(100f, 100f, 25f);
166 maxCoords = new OMV.Vector3(101f, 101f, 26f);
167 minZ = maxZ = 0f;
168 sizeX = sizeY = 256f;
169 }
170 public uint ID;
171 public IntPtr Ptr;
172 public float[] heightMap;
173 public OMV.Vector3 terrainRegionBase;
174 public OMV.Vector3 minCoords;
175 public OMV.Vector3 maxCoords;
176 public float sizeX, sizeY;
177 public float minZ, maxZ;
178 public BulletShape terrainShape;
179 public BulletBody terrainBody;
180}
181
182// The general class of collsion object.
183public enum CollisionType
184{
185 Avatar,
186 Groundplane,
187 Terrain,
188 Static,
189 Dynamic,
190 VolumeDetect,
191 // Linkset, // A linkset should be either Static or Dynamic
192 LinksetChild,
193 Unknown
194};
195
196// Hold specification of group and mask collision flags for a CollisionType
197public struct CollisionTypeFilterGroup
198{
199 public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
200 {
201 type = t;
202 group = g;
203 mask = m;
204 }
205 public CollisionType type;
206 public uint group;
207 public uint mask;
208};
209
210 /* NOTE: old definitions kept for reference. Delete when things are working.
211 // The collsion filters and masked are defined in one place -- don't want them scattered
212 AvatarGroup = BCharacterGroup,
213 AvatarMask = BAllGroup,
214 ObjectGroup = BSolidGroup,
215 ObjectMask = BAllGroup,
216 StaticObjectGroup = BStaticGroup,
217 StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
218 LinksetGroup = BLinksetGroup,
219 LinksetMask = BAllGroup,
220 LinksetChildGroup = BLinksetChildGroup,
221 LinksetChildMask = BNoneGroup, // Linkset children disappear from the world
222 VolumeDetectGroup = BSensorTrigger,
223 VolumeDetectMask = ~BSensorTrigger,
224 TerrainGroup = BTerrainGroup,
225 TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
226 GroundPlaneGroup = BGroundPlaneGroup,
227 GroundPlaneMask = BAllGroup
228 */
229
230public static class BulletSimData
231{
232
233// Map of collisionTypes to flags for collision groups and masks.
234// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
235// but, instead, use references to this dictionary. Finding and debugging
236// collision flag problems will be made easier.
237public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
238 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
239{
240 { CollisionType.Avatar,
241 new CollisionTypeFilterGroup(CollisionType.Avatar,
242 (uint)CollisionFilterGroups.BCharacterGroup,
243 (uint)CollisionFilterGroups.BAllGroup)
244 },
245 { CollisionType.Groundplane,
246 new CollisionTypeFilterGroup(CollisionType.Groundplane,
247 (uint)CollisionFilterGroups.BGroundPlaneGroup,
248 (uint)CollisionFilterGroups.BAllGroup)
249 },
250 { CollisionType.Terrain,
251 new CollisionTypeFilterGroup(CollisionType.Terrain,
252 (uint)CollisionFilterGroups.BTerrainGroup,
253 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
254 },
255 { CollisionType.Static,
256 new CollisionTypeFilterGroup(CollisionType.Static,
257 (uint)CollisionFilterGroups.BStaticGroup,
258 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
259 },
260 { CollisionType.Dynamic,
261 new CollisionTypeFilterGroup(CollisionType.Dynamic,
262 (uint)CollisionFilterGroups.BSolidGroup,
263 (uint)(CollisionFilterGroups.BAllGroup))
264 },
265 { CollisionType.VolumeDetect,
266 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
267 (uint)CollisionFilterGroups.BSensorTrigger,
268 (uint)(~CollisionFilterGroups.BSensorTrigger))
269 },
270 { CollisionType.LinksetChild,
271 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
272 (uint)CollisionFilterGroups.BTerrainGroup,
273 (uint)(CollisionFilterGroups.BNoneGroup))
274 },
275};
276
277}
278}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
index a2161c3..7d6ace8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -11,13 +11,20 @@ CRASHES
11 11
12VEHICLES TODO LIST: 12VEHICLES TODO LIST:
13================================================= 13=================================================
14Neb car jiggling left and right 14Neb vehicle taking > 25ms of physics time!!
15 Happens on terrain and any other mesh object. Flat cubes are much smoother.
16Vehicles (Move smoothly) 15Vehicles (Move smoothly)
17Add vehicle collisions so IsColliding is properly reported. 16Add vehicle collisions so IsColliding is properly reported.
18 Needed for banking, limitMotorUp, movementLimiting, ... 17 Needed for banking, limitMotorUp, movementLimiting, ...
19Some vehicles should not be able to turn if no speed or off ground. 18Some vehicles should not be able to turn if no speed or off ground.
19Neb car jiggling left and right
20 Happens on terrain and any other mesh object. Flat cubes are much smoother.
21 This has been reduced but not eliminated.
22Light cycle falling over when driving
20For limitMotorUp, use raycast down to find if vehicle is in the air. 23For limitMotorUp, use raycast down to find if vehicle is in the air.
24Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
25 Verify that angular motion specified around Z moves in the vehicle coordinates.
26Verify llGetVel() is returning a smooth and good value for vehicle movement.
27llGetVel() should return the root's velocity if requested in a child prim.
21Implement function efficiency for lineaar and angular motion. 28Implement function efficiency for lineaar and angular motion.
22Should vehicle angular/linear movement friction happen after all the components 29Should vehicle angular/linear movement friction happen after all the components
23 or does it only apply to the basic movement? 30 or does it only apply to the basic movement?
@@ -30,15 +37,14 @@ Border crossing with linked vehicle causes crash
30 37
31BULLETSIM TODO LIST: 38BULLETSIM TODO LIST:
32================================================= 39=================================================
40Avatar height off after unsitting (floats off ground)
41 Editting appearance then moving restores.
42 Must not be initializing height when recreating capsule after unsit.
33Duplicating a physical prim causes old prim to jump away 43Duplicating a physical prim causes old prim to jump away
34 Dup a phys prim and the original become unselected and thus interacts w/ selected prim. 44 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
35Disable activity of passive linkset children.
36 Since the linkset is a compound object, the old prims are left lying
37 around and need to be phantomized so they don't collide, ...
38Scenes with hundred of thousands of static objects take a lot of physics CPU time. 45Scenes with hundred of thousands of static objects take a lot of physics CPU time.
39BSPrim.Force should set a continious force on the prim. The force should be 46BSPrim.Force should set a continious force on the prim. The force should be
40 applied each tick. Some limits? 47 applied each tick. Some limits?
41Single prim vehicles don't seem to properly vehiclize.
42Gun sending shooter flying. 48Gun sending shooter flying.
43Collision margin (gap between physical objects lying on each other) 49Collision margin (gap between physical objects lying on each other)
44Boundry checking (crashes related to crossing boundry) 50Boundry checking (crashes related to crossing boundry)
@@ -51,14 +57,34 @@ Small physical objects do not interact correctly
51 The chain will fall apart and pairs will dance around on ground 57 The chain will fall apart and pairs will dance around on ground
52 Chains of 1x1x.2 will stay connected but will dance. 58 Chains of 1x1x.2 will stay connected but will dance.
53 Chains above 2x2x.4 are move stable and get stablier as torui get larger. 59 Chains above 2x2x.4 are move stable and get stablier as torui get larger.
54Add material type linkage and input all the material property definitions.
55 Skeleton classes and table are in the sources but are not filled or used.
56Add PID motor for avatar movement (slow to stop, ...) 60Add PID motor for avatar movement (slow to stop, ...)
57setForce should set a constant force. Different than AddImpulse. 61setForce should set a constant force. Different than AddImpulse.
58Implement raycast. 62Implement raycast.
59Implement ShapeCollection.Dispose() 63Implement ShapeCollection.Dispose()
60Implement water as a plain so raycasting and collisions can happen with same. 64Implement water as a plain so raycasting and collisions can happen with same.
65Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
66 Also osGetPhysicsEngineVerion() maybe.
67
68LINKSETS
69======================================================
70Linksets should allow collisions to individual children
71 Add LocalID to children shapes in LinksetCompound and create events for individuals
72Verify/think through scripts in children of linksets. What do they reference
73 and return when getting position, velocity, ...
74Confirm constraint linksets still work after making all the changes for compound linksets.
75Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
76 For compound linksets, add ability to remove or reposition individual child shapes.
77Disable activity of passive linkset children.
78 Since the linkset is a compound object, the old prims are left lying
79 around and need to be phantomized so they don't collide, ...
80Speed up creation of large physical linksets
81 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical
82Eliminate collisions between objects in a linkset. (LinksetConstraint)
83 Have UserPointer point to struct with localID and linksetID?
84 Objects in original linkset still collide with each other?
61 85
86MORE
87======================================================
62Find/remove avatar collision with ID=0. 88Find/remove avatar collision with ID=0.
63Test avatar walking up stairs. How does compare with SL. 89Test avatar walking up stairs. How does compare with SL.
64 Radius of the capsule affects ability to climb edges. 90 Radius of the capsule affects ability to climb edges.
@@ -67,8 +93,6 @@ Debounce avatar contact so legs don't keep folding up when standing.
67Implement LSL physics controls. Like STATUS_ROTATE_X. 93Implement LSL physics controls. Like STATUS_ROTATE_X.
68Add border extensions to terrain to help region crossings and objects leaving region. 94Add border extensions to terrain to help region crossings and objects leaving region.
69 95
70Speed up creation of large physical linksets
71 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical
72Performance test with lots of avatars. Can BulletSim support a thousand? 96Performance test with lots of avatars. Can BulletSim support a thousand?
73Optimize collisions in C++: only send up to the object subscribed to collisions. 97Optimize collisions in C++: only send up to the object subscribed to collisions.
74 Use collision subscription and remove the collsion(A,B) and collision(B,A) 98 Use collision subscription and remove the collsion(A,B) and collision(B,A)
@@ -79,10 +103,6 @@ Avatar jump
79Performance measurement and changes to make quicker. 103Performance measurement and changes to make quicker.
80Implement detailed physics stats (GetStats()). 104Implement detailed physics stats (GetStats()).
81 105
82Eliminate collisions between objects in a linkset. (LinksetConstraint)
83 Have UserPointer point to struct with localID and linksetID?
84 Objects in original linkset still collide with each other?
85
86Measure performance improvement from hulls 106Measure performance improvement from hulls
87Test not using ghost objects for volume detect implementation. 107Test not using ghost objects for volume detect implementation.
88Performance of closures and delegates for taint processing 108Performance of closures and delegates for taint processing
@@ -95,10 +115,16 @@ Physics Arena central pyramid: why is one side permiable?
95 115
96INTERNAL IMPROVEMENT/CLEANUP 116INTERNAL IMPROVEMENT/CLEANUP
97================================================= 117=================================================
118Consider moving prim/character body and shape destruction in destroy()
119 to postTimeTime rather than protecting all the potential sets that
120 might have been queued up.
98Remove unused fields from ShapeData (not used in API2) 121Remove unused fields from ShapeData (not used in API2)
99Breakout code for mesh/hull/compound/native into separate BSShape* classes 122Breakout code for mesh/hull/compound/native into separate BSShape* classes
100 Standardize access to building and reference code. 123 Standardize access to building and reference code.
101 The skeleton classes are in the sources but are not complete or linked in. 124 The skeleton classes are in the sources but are not complete or linked in.
125Make BSBody and BSShape real classes to centralize creation/changin/destruction
126 Convert state and parameter calls from BulletSimAPI direct calls to
127 calls on BSBody and BSShape
102Generalize Dynamics and PID with standardized motors. 128Generalize Dynamics and PID with standardized motors.
103Generalize Linkset and vehicles into PropertyManagers 129Generalize Linkset and vehicles into PropertyManagers
104 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies 130 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
@@ -110,7 +136,7 @@ Implement linkset by setting position of children when root updated. (LinksetMan
110 Linkset implementation using manual prim movement. 136 Linkset implementation using manual prim movement.
111LinkablePrim class? Would that simplify/centralize the linkset logic? 137LinkablePrim class? Would that simplify/centralize the linkset logic?
112BSScene.UpdateParameterSet() is broken. How to set params on objects? 138BSScene.UpdateParameterSet() is broken. How to set params on objects?
113Remove HeightmapInfo from terrain specification. 139Remove HeightmapInfo from terrain specification
114 Since C++ code does not need terrain height, this structure et al are not needed. 140 Since C++ code does not need terrain height, this structure et al are not needed.
115Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will 141Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
116 bob at the water level. BSPrim.PositionSanityCheck(). 142 bob at the water level. BSPrim.PositionSanityCheck().
@@ -142,7 +168,11 @@ Do prim hash codes work for sculpties and meshes? (Resolution: yes)
142Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound) 168Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
143 Compound shapes will need the LocalID in the shapes and collision 169 Compound shapes will need the LocalID in the shapes and collision
144 processing to get it from there. 170 processing to get it from there.
145Light cycle falling over when driving (Resolution: implemented VerticalAttractor)
146Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.) 171Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
147Package Bullet source mods for Bullet internal stats output 172Package Bullet source mods for Bullet internal stats output
148 (Resolution: move code into WorldData.h rather than relying on patches) \ No newline at end of file 173 (Resolution: move code into WorldData.h rather than relying on patches)
174Single prim vehicles don't seem to properly vehiclize.
175 (Resolution: mass was not getting set properly for single prim linksets)
176Add material type linkage and input all the material property definitions.
177 Skeleton classes and table are in the sources but are not filled or used.
178 (Resolution:
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
index 5af6373..be36be3 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
@@ -333,17 +333,20 @@ namespace OpenSim.Region.Physics.Manager
333 } 333 }
334 334
335 /// <summary> 335 /// <summary>
336 /// Velocity of this actor. 336 /// The desired velocity of this actor.
337 /// </summary> 337 /// </summary>
338 /// <remarks> 338 /// <remarks>
339 /// Setting this provides a target velocity for physics scene updates. 339 /// Setting this provides a target velocity for physics scene updates.
340 /// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity, 340 /// Getting this returns the last set target. Fetch Velocity to get the current velocity.
341 /// time to accelerate and collisions.
342 /// </remarks> 341 /// </remarks>
342 protected Vector3 m_targetVelocity;
343 public virtual Vector3 TargetVelocity 343 public virtual Vector3 TargetVelocity
344 { 344 {
345 get { return Velocity; } 345 get { return m_targetVelocity; }
346 set { Velocity = value; } 346 set {
347 m_targetVelocity = value;
348 Velocity = m_targetVelocity;
349 }
347 } 350 }
348 351
349 public abstract Vector3 Velocity { get; set; } 352 public abstract Vector3 Velocity { get; set; }
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index 0cef550..00a99c3 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -59,6 +59,18 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
59 public interface IScriptInstance 59 public interface IScriptInstance
60 { 60 {
61 /// <summary> 61 /// <summary>
62 /// Debug level for this script instance.
63 /// </summary>
64 /// <remarks>
65 /// Level == 0, no extra data is logged.
66 /// Level >= 1, state changes are logged.
67 /// Level >= 2, event firing is logged.
68 /// <value>
69 /// The debug level.
70 /// </value>
71 int DebugLevel { get; set; }
72
73 /// <summary>
62 /// Is the script currently running? 74 /// Is the script currently running?
63 /// </summary> 75 /// </summary>
64 bool Running { get; set; } 76 bool Running { get; set; }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 538cb8b..68f701c 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -94,6 +94,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
94 private UUID m_CurrentStateHash; 94 private UUID m_CurrentStateHash;
95 private UUID m_RegionID; 95 private UUID m_RegionID;
96 96
97 public int DebugLevel { get; set; }
98
97 public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; } 99 public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; }
98 100
99 private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>(); 101 private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>();
@@ -549,9 +551,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
549 // forcibly abort the work item (this aborts the underlying thread). 551 // forcibly abort the work item (this aborts the underlying thread).
550 if (!m_InSelfDelete) 552 if (!m_InSelfDelete)
551 { 553 {
552// m_log.ErrorFormat( 554 m_log.DebugFormat(
553// "[SCRIPT INSTANCE]: Aborting script {0} {1} in prim {2} {3} {4} {5}", 555 "[SCRIPT INSTANCE]: Aborting unstopped script {0} {1} in prim {2}, localID {3}, timeout was {4} ms",
554// ScriptName, ItemID, PrimName, ObjectID, m_InSelfDelete, DateTime.Now.Ticks); 556 ScriptName, ItemID, PrimName, LocalID, timeout);
555 557
556 workItem.Abort(); 558 workItem.Abort();
557 } 559 }
@@ -707,19 +709,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
707 { 709 {
708 710
709// m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this); 711// m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this);
712 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID);
713
714 if (DebugLevel >= 2)
715 m_log.DebugFormat(
716 "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
717 data.EventName,
718 ScriptName,
719 part.Name,
720 part.LocalId,
721 part.ParentGroup.Name,
722 part.ParentGroup.UUID,
723 part.AbsolutePosition,
724 part.ParentGroup.Scene.Name);
710 725
711 m_DetectParams = data.DetectParams; 726 m_DetectParams = data.DetectParams;
712 727
713 if (data.EventName == "state") // Hardcoded state change 728 if (data.EventName == "state") // Hardcoded state change
714 { 729 {
715 // m_log.DebugFormat("[Script] Script {0}.{1} state set to {2}",
716 // PrimName, ScriptName, data.Params[0].ToString());
717 State = data.Params[0].ToString(); 730 State = data.Params[0].ToString();
731
732 if (DebugLevel >= 1)
733 m_log.DebugFormat(
734 "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
735 State,
736 ScriptName,
737 part.Name,
738 part.LocalId,
739 part.ParentGroup.Name,
740 part.ParentGroup.UUID,
741 part.AbsolutePosition,
742 part.ParentGroup.Scene.Name);
743
718 AsyncCommandManager.RemoveScript(Engine, 744 AsyncCommandManager.RemoveScript(Engine,
719 LocalID, ItemID); 745 LocalID, ItemID);
720 746
721 SceneObjectPart part = Engine.World.GetSceneObjectPart(
722 LocalID);
723 if (part != null) 747 if (part != null)
724 { 748 {
725 part.SetScriptEvents(ItemID, 749 part.SetScriptEvents(ItemID,
@@ -731,8 +755,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
731 if (Engine.World.PipeEventsForScript(LocalID) || 755 if (Engine.World.PipeEventsForScript(LocalID) ||
732 data.EventName == "control") // Don't freeze avies! 756 data.EventName == "control") // Don't freeze avies!
733 { 757 {
734 SceneObjectPart part = Engine.World.GetSceneObjectPart(
735 LocalID);
736 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", 758 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
737 // PrimName, ScriptName, data.EventName, State); 759 // PrimName, ScriptName, data.EventName, State);
738 760
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 05ba890..494e0b6 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -108,6 +108,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine
108 private IXmlRpcRouter m_XmlRpcRouter; 108 private IXmlRpcRouter m_XmlRpcRouter;
109 private int m_EventLimit; 109 private int m_EventLimit;
110 private bool m_KillTimedOutScripts; 110 private bool m_KillTimedOutScripts;
111
112 /// <summary>
113 /// Number of milliseconds we will wait for a script event to complete on script stop before we forcibly abort
114 /// its thread.
115 /// </summary>
116 /// <remarks>
117 /// It appears that if a script thread is aborted whilst it is holding ReaderWriterLockSlim (possibly the write
118 /// lock) then the lock is not properly released. This causes mono 2.6, 2.10 and possibly
119 /// later to crash, sometimes with symptoms such as a leap to 100% script usage and a vm thead dump showing
120 /// all threads waiting on release of ReaderWriterLockSlim write thread which none of the threads listed
121 /// actually hold.
122 ///
123 /// Pausing for event completion reduces the risk of this happening. However, it may be that aborting threads
124 /// is not a mono issue per se but rather a risky activity in itself in an AppDomain that is not immediately
125 /// shutting down.
126 /// </remarks>
127 private int m_WaitForEventCompletionOnScriptStop = 1000;
128
111 private string m_ScriptEnginesPath = null; 129 private string m_ScriptEnginesPath = null;
112 130
113 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>(); 131 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>();
@@ -317,6 +335,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
317 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); 335 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
318 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); 336 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
319 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000; 337 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000;
338 m_WaitForEventCompletionOnScriptStop
339 = m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop);
340
320 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines"); 341 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines");
321 342
322 m_Prio = ThreadPriority.BelowNormal; 343 m_Prio = ThreadPriority.BelowNormal;
@@ -372,7 +393,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
372 393
373 MainConsole.Instance.Commands.AddCommand( 394 MainConsole.Instance.Commands.AddCommand(
374 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information", 395 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information",
375 "Show information on all scripts known to the script engine." 396 "Show information on all scripts known to the script engine.\n"
376 + "If a <script-item-uuid> is given then only information on that script will be shown.", 397 + "If a <script-item-uuid> is given then only information on that script will be shown.",
377 HandleShowScripts); 398 HandleShowScripts);
378 399
@@ -391,22 +412,30 @@ namespace OpenSim.Region.ScriptEngine.XEngine
391 MainConsole.Instance.Commands.AddCommand( 412 MainConsole.Instance.Commands.AddCommand(
392 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts", 413 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts",
393 "Resumes all currently suspended scripts.\n" 414 "Resumes all currently suspended scripts.\n"
394 + "Resumed scripts will process all events accumulated whilst suspended." 415 + "Resumed scripts will process all events accumulated whilst suspended.\n"
395 + "If a <script-item-uuid> is given then only that script will be resumed. Otherwise, all suitable scripts are resumed.", 416 + "If a <script-item-uuid> is given then only that script will be resumed. Otherwise, all suitable scripts are resumed.",
396 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript)); 417 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript));
397 418
398 MainConsole.Instance.Commands.AddCommand( 419 MainConsole.Instance.Commands.AddCommand(
399 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts", 420 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts",
400 "Stops all running scripts." 421 "Stops all running scripts.\n"
401 + "If a <script-item-uuid> is given then only that script will be stopped. Otherwise, all suitable scripts are stopped.", 422 + "If a <script-item-uuid> is given then only that script will be stopped. Otherwise, all suitable scripts are stopped.",
402 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript)); 423 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript));
403 424
404 MainConsole.Instance.Commands.AddCommand( 425 MainConsole.Instance.Commands.AddCommand(
405 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts", 426 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts",
406 "Starts all stopped scripts." 427 "Starts all stopped scripts.\n"
407 + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.", 428 + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.",
408 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); 429 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
409 430
431 MainConsole.Instance.Commands.AddCommand(
432 "Scripts", false, "debug script log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script",
433 "Activates or deactivates extra debug logging for the given script.\n"
434 + "Level == 0, deactivate extra debug logging.\n"
435 + "Level >= 1, log state changes.\n"
436 + "Level >= 2, log event invocations.\n",
437 HandleDebugScriptLogCommand);
438
410// MainConsole.Instance.Commands.AddCommand( 439// MainConsole.Instance.Commands.AddCommand(
411// "Debug", false, "debug xengine", "debug xengine [<level>]", 440// "Debug", false, "debug xengine", "debug xengine [<level>]",
412// "Turn on detailed xengine debugging.", 441// "Turn on detailed xengine debugging.",
@@ -415,6 +444,41 @@ namespace OpenSim.Region.ScriptEngine.XEngine
415// HandleDebugLevelCommand); 444// HandleDebugLevelCommand);
416 } 445 }
417 446
447 private void HandleDebugScriptLogCommand(string module, string[] args)
448 {
449 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
450 return;
451
452 if (args.Length != 5)
453 {
454 MainConsole.Instance.Output("Usage: debug script log <item-id> <log-level>");
455 return;
456 }
457
458 UUID itemId;
459
460 if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, args[3], out itemId))
461 return;
462
463 int newLevel;
464
465 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out newLevel))
466 return;
467
468 IScriptInstance si;
469
470 lock (m_Scripts)
471 {
472 // XXX: We can't give the user feedback on a bad item id because this may apply to a different script
473 // engine
474 if (!m_Scripts.TryGetValue(itemId, out si))
475 return;
476 }
477
478 si.DebugLevel = newLevel;
479 MainConsole.Instance.OutputFormat("Set debug level of {0} {1} to {2}", si.ScriptName, si.ItemID, newLevel);
480 }
481
418 /// <summary> 482 /// <summary>
419 /// Change debug level 483 /// Change debug level
420 /// </summary> 484 /// </summary>
@@ -486,7 +550,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
486 550
487 if (!UUID.TryParse(rawItemId, out itemId)) 551 if (!UUID.TryParse(rawItemId, out itemId))
488 { 552 {
489 MainConsole.Instance.OutputFormat("Error - {0} is not a valid UUID", rawItemId); 553 MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId);
490 return; 554 return;
491 } 555 }
492 556
@@ -610,6 +674,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
610 sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued); 674 sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
611 sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed); 675 sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed);
612 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID); 676 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
677 sb.AppendFormat("Asset UUID : {0}\n", instance.AssetID);
613 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName); 678 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
614 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); 679 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
615 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); 680 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition);
@@ -1375,9 +1440,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1375 lockScriptsForWrite(false); 1440 lockScriptsForWrite(false);
1376 instance.ClearQueue(); 1441 instance.ClearQueue();
1377 1442
1378 // Give the script some time to finish processing its last event. Simply aborting the script thread can 1443 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1379 // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
1380 instance.Stop(1000);
1381 1444
1382// bool objectRemoved = false; 1445// bool objectRemoved = false;
1383 1446
@@ -1735,16 +1798,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1735 public void StopScript(UUID itemID) 1798 public void StopScript(UUID itemID)
1736 { 1799 {
1737 IScriptInstance instance = GetInstance(itemID); 1800 IScriptInstance instance = GetInstance(itemID);
1801
1738 if (instance != null) 1802 if (instance != null)
1739 { 1803 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1740 // Give the script some time to finish processing its last event. Simply aborting the script thread can
1741 // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
1742 instance.Stop(1000);
1743 }
1744 else 1804 else
1745 {
1746 m_runFlags.AddOrUpdate(itemID, false, 240); 1805 m_runFlags.AddOrUpdate(itemID, false, 240);
1747 }
1748 } 1806 }
1749 1807
1750 public DetectParams GetDetectParams(UUID itemID, int idx) 1808 public DetectParams GetDetectParams(UUID itemID, int idx)
diff --git a/OpenSim/Region/UserStatistics/WebStatsModule.cs b/OpenSim/Region/UserStatistics/WebStatsModule.cs
index b08233c..64cb577 100644
--- a/OpenSim/Region/UserStatistics/WebStatsModule.cs
+++ b/OpenSim/Region/UserStatistics/WebStatsModule.cs
@@ -94,8 +94,6 @@ namespace OpenSim.Region.UserStatistics
94 if (!enabled) 94 if (!enabled)
95 return; 95 return;
96 96
97 AddEventHandlers();
98
99 if (Util.IsWindows()) 97 if (Util.IsWindows())
100 Util.LoadArchSpecificWindowsDll("sqlite3.dll"); 98 Util.LoadArchSpecificWindowsDll("sqlite3.dll");
101 99
@@ -143,10 +141,14 @@ namespace OpenSim.Region.UserStatistics
143 lock (m_scenes) 141 lock (m_scenes)
144 { 142 {
145 m_scenes.Add(scene); 143 m_scenes.Add(scene);
146 if (m_simstatsCounters.ContainsKey(scene.RegionInfo.RegionID)) 144 updateLogMod = m_scenes.Count * 2;
147 m_simstatsCounters.Remove(scene.RegionInfo.RegionID);
148 145
149 m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID)); 146 m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID));
147
148 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
149 scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps;
150 scene.EventManager.OnClientClosed += OnClientClosed;
151 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
150 scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket; 152 scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket;
151 } 153 }
152 } 154 }
@@ -157,6 +159,15 @@ namespace OpenSim.Region.UserStatistics
157 159
158 public void RemoveRegion(Scene scene) 160 public void RemoveRegion(Scene scene)
159 { 161 {
162 if (!enabled)
163 return;
164
165 lock (m_scenes)
166 {
167 m_scenes.Remove(scene);
168 updateLogMod = m_scenes.Count * 2;
169 m_simstatsCounters.Remove(scene.RegionInfo.RegionID);
170 }
160 } 171 }
161 172
162 public virtual void Close() 173 public virtual void Close()
@@ -187,9 +198,7 @@ namespace OpenSim.Region.UserStatistics
187 private void ReceiveClassicSimStatsPacket(SimStats stats) 198 private void ReceiveClassicSimStatsPacket(SimStats stats)
188 { 199 {
189 if (!enabled) 200 if (!enabled)
190 {
191 return; 201 return;
192 }
193 202
194 try 203 try
195 { 204 {
@@ -198,17 +207,25 @@ namespace OpenSim.Region.UserStatistics
198 if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000) 207 if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000)
199 return; 208 return;
200 209
201 if ((updateLogCounter++ % updateLogMod) == 0) 210 // We will conduct this under lock so that fields such as updateLogCounter do not potentially get
211 // confused if a scene is removed.
212 // XXX: Possibly the scope of this lock could be reduced though it's not critical.
213 lock (m_scenes)
202 { 214 {
203 m_loglines = readLogLines(10); 215 if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0)
204 if (updateLogCounter > 10000) updateLogCounter = 1; 216 {
205 } 217 m_loglines = readLogLines(10);
206 218
207 USimStatsData ss = m_simstatsCounters[stats.RegionUUID]; 219 if (updateLogCounter > 10000)
220 updateLogCounter = 1;
221 }
208 222
209 if ((++ss.StatsCounter % updateStatsMod) == 0) 223 USimStatsData ss = m_simstatsCounters[stats.RegionUUID];
210 { 224
211 ss.ConsumeSimStats(stats); 225 if ((++ss.StatsCounter % updateStatsMod) == 0)
226 {
227 ss.ConsumeSimStats(stats);
228 }
212 } 229 }
213 } 230 }
214 catch (KeyNotFoundException) 231 catch (KeyNotFoundException)
diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs
index 31b0446..3f208bf 100644
--- a/OpenSim/Server/Base/ServerUtils.cs
+++ b/OpenSim/Server/Base/ServerUtils.cs
@@ -89,12 +89,39 @@ namespace OpenSim.Server.Base
89 Config = config; 89 Config = config;
90 90
91 Registry = new AddinRegistry(registryPath, "."); 91 Registry = new AddinRegistry(registryPath, ".");
92 suppress_console_output_(true);
92 AddinManager.Initialize(registryPath); 93 AddinManager.Initialize(registryPath);
94 suppress_console_output_(false);
93 AddinManager.Registry.Update(); 95 AddinManager.Registry.Update();
94 CommandManager commandmanager = new CommandManager(Registry); 96 CommandManager commandmanager = new CommandManager(Registry);
95 AddinManager.AddExtensionNodeHandler("/Robust/Connector", OnExtensionChanged); 97 AddinManager.AddExtensionNodeHandler("/Robust/Connector", OnExtensionChanged);
96 } 98 }
97 99
100 private static TextWriter prev_console_;
101 // Temporarily masking the errors reported on start
102 // This is caused by a non-managed dll in the ./bin dir
103 // when the registry is initialized. The dll belongs to
104 // libomv, which has a hard-coded path to "." for pinvoke
105 // to load the openjpeg dll
106 //
107 // Will look for a way to fix, but for now this keeps the
108 // confusion to a minimum. this was copied from our region
109 // plugin loader, we have been doing this in there for a long time.
110 //
111 public void suppress_console_output_(bool save)
112 {
113 if (save)
114 {
115 prev_console_ = System.Console.Out;
116 System.Console.SetOut(new StreamWriter(Stream.Null));
117 }
118 else
119 {
120 if (prev_console_ != null)
121 System.Console.SetOut(prev_console_);
122 }
123 }
124
98 private void OnExtensionChanged(object s, ExtensionNodeEventArgs args) 125 private void OnExtensionChanged(object s, ExtensionNodeEventArgs args)
99 { 126 {
100 IRobustConnector connector = (IRobustConnector)args.ExtensionObject; 127 IRobustConnector connector = (IRobustConnector)args.ExtensionObject;
@@ -112,8 +139,7 @@ namespace OpenSim.Server.Base
112 if (a.AddinFile.Contains(Registry.DefaultAddinsFolder)) 139 if (a.AddinFile.Contains(Registry.DefaultAddinsFolder))
113 { 140 {
114 m_log.InfoFormat("[SERVER]: Adding {0} from registry", a.Name); 141 m_log.InfoFormat("[SERVER]: Adding {0} from registry", a.Name);
115 connector.PluginPath = String.Format("{0}/{1}", Registry.DefaultAddinsFolder, a.Name.Replace(',', '.')); 142 connector.PluginPath = System.IO.Path.Combine(Registry.DefaultAddinsFolder,a.Name.Replace(',', '.')); }
116 }
117 else 143 else
118 { 144 {
119 m_log.InfoFormat("[SERVER]: Adding {0} from ./bin", a.Name); 145 m_log.InfoFormat("[SERVER]: Adding {0} from ./bin", a.Name);
@@ -189,20 +215,30 @@ namespace OpenSim.Server.Base
189 /// <param name="dllName"></param> 215 /// <param name="dllName"></param>
190 /// <param name="args">The arguments which control which constructor is invoked on the plugin</param> 216 /// <param name="args">The arguments which control which constructor is invoked on the plugin</param>
191 /// <returns></returns> 217 /// <returns></returns>
192 public static T LoadPlugin<T>(string dllName, Object[] args) where T:class 218 public static T LoadPlugin<T> (string dllName, Object[] args) where T:class
193 { 219 {
194 // This is good to debug configuration problems 220 // This is good to debug configuration problems
195 //if (dllName == string.Empty) 221 //if (dllName == string.Empty)
196 // Util.PrintCallStack(); 222 // Util.PrintCallStack();
197 223
198 string[] parts = dllName.Split(new char[] {':'});
199
200 dllName = parts[0];
201
202 string className = String.Empty; 224 string className = String.Empty;
203 225
204 if (parts.Length > 1) 226 // The path for a dynamic plugin will contain ":" on Windows
205 className = parts[1]; 227 string[] parts = dllName.Split (new char[] {':'});
228
229 if (parts [0].Length > 1)
230 {
231 dllName = parts [0];
232 if (parts.Length > 1)
233 className = parts[1];
234 }
235 else
236 {
237 // This is Windows - we must replace the ":" in the path
238 dllName = String.Format ("{0}:{1}", parts [0], parts [1]);
239 if (parts.Length > 2)
240 className = parts[2];
241 }
206 242
207 return LoadPlugin<T>(dllName, className, args); 243 return LoadPlugin<T>(dllName, className, args);
208 } 244 }