aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-07-27 00:30:04 +0100
committerJustin Clark-Casey (justincc)2012-07-27 00:30:04 +0100
commit5f741143fd328e8b13b512d9cc611178433eaef7 (patch)
tree06f919ea81fdd26918f64fc50521b0dc0ffedd40 /OpenSim/Region/Physics
parentFix issue where RegionCombinerModule was not removing regions from its dictio... (diff)
parentBulletSim: fix a recursive loop when fetching the mass of the root of a linkset. (diff)
downloadopensim-SC_OLD-5f741143fd328e8b13b512d9cc611178433eaef7.zip
opensim-SC_OLD-5f741143fd328e8b13b512d9cc611178433eaef7.tar.gz
opensim-SC_OLD-5f741143fd328e8b13b512d9cc611178433eaef7.tar.bz2
opensim-SC_OLD-5f741143fd328e8b13b512d9cc611178433eaef7.tar.xz
Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
Diffstat (limited to 'OpenSim/Region/Physics')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs308
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs327
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs7
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs2
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs9
5 files changed, 418 insertions, 235 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
new file mode 100755
index 0000000..3bc2100
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -0,0 +1,308 @@
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;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public class BSLinkset
36{
37 private static string LogHeader = "[BULLETSIM LINKSET]";
38
39 private BSPrim m_linksetRoot;
40 public BSPrim Root { get { return m_linksetRoot; } }
41
42 private BSScene m_scene;
43
44 private List<BSPrim> m_children;
45
46 // We lock the diddling of linkset classes to prevent any badness.
47 // This locks the modification of the instances of this class. Changes
48 // to the physical representation is done via the tainting mechenism.
49 private object m_linksetActivityLock = new Object();
50
51 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
52 private float m_mass;
53 public float LinksetMass
54 {
55 get
56 {
57 m_mass = ComputeLinksetMass();
58 return m_mass;
59 }
60 }
61
62 public OMV.Vector3 CenterOfMass
63 {
64 get { return ComputeLinksetCenterOfMass(); }
65 }
66
67 public OMV.Vector3 GeometricCenter
68 {
69 get { return ComputeLinksetGeometricCenter(); }
70 }
71
72 public BSLinkset(BSScene scene, BSPrim parent)
73 {
74 // A simple linkset of one (no children)
75 m_scene = scene;
76 m_linksetRoot = parent;
77 m_children = new List<BSPrim>();
78 m_mass = parent.MassRaw;
79 }
80
81 // Link to a linkset where the child knows the parent.
82 // Parent changing should not happen so do some sanity checking.
83 // We return the parent's linkset so the child can track it's membership.
84 public BSLinkset AddMeToLinkset(BSPrim child, BSPrim parent)
85 {
86 lock (m_linksetActivityLock)
87 {
88 parent.Linkset.AddChildToLinkset(child);
89 }
90 return parent.Linkset;
91 }
92
93 public BSLinkset RemoveMeFromLinkset(BSPrim child)
94 {
95 lock (m_linksetActivityLock)
96 {
97 if (IsRoot(child))
98 {
99 // if root of linkset, take the linkset apart
100 while (m_children.Count > 0)
101 {
102 // Note that we don't do a foreach because the remove routine
103 // takes it out of the list.
104 RemoveChildFromLinkset(m_children[0]);
105 }
106 m_children.Clear(); // just to make sure
107 }
108 else
109 {
110 // Just removing a child from an existing linkset
111 RemoveChildFromLinkset(child);
112 }
113 }
114
115 // The child is down to a linkset of just itself
116 return new BSLinkset(m_scene, child);
117 }
118
119 // An existing linkset had one of its members rebuilt or something.
120 // Undo all the physical linking and rebuild the physical linkset.
121 public bool RefreshLinkset(BSPrim requestor)
122 {
123 return true;
124 }
125
126
127 // Return 'true' if the passed object is the root object of this linkset
128 public bool IsRoot(BSPrim requestor)
129 {
130 return (requestor.LocalID == m_linksetRoot.LocalID);
131 }
132
133 // Return 'true' if this linkset has any children (more than the root member)
134 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
135
136 // Return 'true' if this child is in this linkset
137 public bool HasChild(BSPrim child)
138 {
139 bool ret = false;
140 foreach (BSPrim bp in m_children)
141 {
142 if (child.LocalID == bp.LocalID)
143 {
144 ret = true;
145 break;
146 }
147 }
148 return ret;
149 }
150
151 private float ComputeLinksetMass()
152 {
153 float mass = m_linksetRoot.MassRaw;
154 foreach (BSPrim bp in m_children)
155 {
156 mass += bp.MassRaw;
157 }
158 return mass;
159 }
160
161 private OMV.Vector3 ComputeLinksetCenterOfMass()
162 {
163 OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw;
164 float totalMass = m_linksetRoot.MassRaw;
165
166 foreach (BSPrim bp in m_children)
167 {
168 com += bp.Position * bp.MassRaw;
169 totalMass += bp.MassRaw;
170 }
171 com /= totalMass;
172
173 return com;
174 }
175
176 private OMV.Vector3 ComputeLinksetGeometricCenter()
177 {
178 OMV.Vector3 com = m_linksetRoot.Position;
179
180 foreach (BSPrim bp in m_children)
181 {
182 com += bp.Position * bp.MassRaw;
183 }
184 com /= m_children.Count + 1;
185
186 return com;
187 }
188
189 // I am the root of a linkset and a new child is being added
190 public void AddChildToLinkset(BSPrim pchild)
191 {
192 BSPrim child = pchild;
193 if (!HasChild(child))
194 {
195 m_children.Add(child);
196
197 m_scene.TaintedObject(delegate()
198 {
199 DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID);
200 DetailLog("{0},AddChildToLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
201 PhysicallyLinkAChildToRoot(pchild); // build the physical binding between me and the child
202 });
203 }
204 return;
205 }
206
207 // I am the root of a linkset and one of my children is being removed.
208 // Safe to call even if the child is not really in my linkset.
209 public void RemoveChildFromLinkset(BSPrim pchild)
210 {
211 BSPrim child = pchild;
212
213 if (m_children.Remove(child))
214 {
215 m_scene.TaintedObject(delegate()
216 {
217 DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
218 DetailLog("{0},RemoveChildFromLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
219
220 if (m_children.Count == 0)
221 {
222 // if the linkset is empty, make sure all linkages have been removed
223 PhysicallyUnlinkAllChildrenFromRoot();
224 }
225 else
226 {
227 PhysicallyUnlinkAChildFromRoot(pchild);
228 }
229 });
230 }
231 else
232 {
233 // This will happen if we remove the root of the linkset first. Non-fatal occurance.
234 // m_scene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
235 }
236 return;
237 }
238
239 // Create a constraint between me (root of linkset) and the passed prim (the child).
240 // Called at taint time!
241 private void PhysicallyLinkAChildToRoot(BSPrim childPrim)
242 {
243 // Zero motion for children so they don't interpolate
244 childPrim.ZeroMotion();
245
246 // relative position normalized to the root prim
247 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(m_linksetRoot.Orientation);
248 OMV.Vector3 childRelativePosition = (childPrim.Position - m_linksetRoot.Position) * invThisOrientation;
249
250 // relative rotation of the child to the parent
251 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
252
253 // create a constraint that allows no freedom of movement between the two objects
254 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
255 // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
256 DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
257 BSConstraint constrain = m_scene.Constraints.CreateConstraint(
258 m_scene.World, m_linksetRoot.Body, childPrim.Body,
259 childRelativePosition,
260 childRelativeRotation,
261 OMV.Vector3.Zero,
262 OMV.Quaternion.Identity);
263 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
264 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
265
266 // tweek the constraint to increase stability
267 constrain.UseFrameOffset(m_scene.BoolNumeric(m_scene.Params.linkConstraintUseFrameOffset));
268 constrain.TranslationalLimitMotor(m_scene.BoolNumeric(m_scene.Params.linkConstraintEnableTransMotor),
269 m_scene.Params.linkConstraintTransMotorMaxVel,
270 m_scene.Params.linkConstraintTransMotorMaxForce);
271
272 }
273
274 // Remove linkage between myself and a particular child
275 // Called at taint time!
276 private void PhysicallyUnlinkAChildFromRoot(BSPrim childPrim)
277 {
278 DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}",
279 LogHeader, m_linksetRoot.LocalID, childPrim.LocalID);
280 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
281 // BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID);
282 m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body, childPrim.Body);
283 }
284
285 // Remove linkage between myself and any possible children I might have
286 // Called at taint time!
287 private void PhysicallyUnlinkAllChildrenFromRoot()
288 {
289 // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader);
290 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", m_linksetRoot.LocalID);
291 m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body);
292 // BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID);
293 }
294
295 // Invoke the detailed logger and output something if it's enabled.
296 private void DebugLog(string msg, params Object[] args)
297 {
298 m_scene.Logger.DebugFormat(msg, args);
299 }
300
301 // Invoke the detailed logger and output something if it's enabled.
302 private void DetailLog(string msg, params Object[] args)
303 {
304 m_scene.PhysicsLogging.Write(msg, args);
305 }
306
307}
308}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 3be28e3..7590d93 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -66,7 +66,7 @@ public sealed class BSPrim : PhysicsActor
66 private bool _isSelected; 66 private bool _isSelected;
67 private bool _isVolumeDetect; 67 private bool _isVolumeDetect;
68 private OMV.Vector3 _position; 68 private OMV.Vector3 _position;
69 private float _mass; 69 private float _mass; // the mass of this object
70 private float _density; 70 private float _density;
71 private OMV.Vector3 _force; 71 private OMV.Vector3 _force;
72 private OMV.Vector3 _velocity; 72 private OMV.Vector3 _velocity;
@@ -89,8 +89,13 @@ public sealed class BSPrim : PhysicsActor
89 private bool _kinematic; 89 private bool _kinematic;
90 private float _buoyancy; 90 private float _buoyancy;
91 91
92 private BSPrim _parentPrim; 92 // Membership in a linkset is controlled by this class.
93 private List<BSPrim> _childrenPrims; 93 private BSLinkset _linkset;
94 public BSLinkset Linkset
95 {
96 get { return _linkset; }
97 set { _linkset = value; }
98 }
94 99
95 private int _subscribedEventsMs = 0; 100 private int _subscribedEventsMs = 0;
96 private int _nextCollisionOkTime = 0; 101 private int _nextCollisionOkTime = 0;
@@ -133,9 +138,8 @@ public sealed class BSPrim : PhysicsActor
133 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material 138 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material
134 _density = _scene.Params.defaultDensity; // TODO: compute based on object material 139 _density = _scene.Params.defaultDensity; // TODO: compute based on object material
135 _restitution = _scene.Params.defaultRestitution; 140 _restitution = _scene.Params.defaultRestitution;
136 _parentPrim = null; // not a child or a parent 141 _linkset = new BSLinkset(_scene, this); // a linkset of one
137 _vehicle = new BSDynamics(this); // add vehicleness 142 _vehicle = new BSDynamics(this); // add vehicleness
138 _childrenPrims = new List<BSPrim>();
139 _mass = CalculateMass(); 143 _mass = CalculateMass();
140 // do the actual object creation at taint time 144 // do the actual object creation at taint time
141 _scene.TaintedObject(delegate() 145 _scene.TaintedObject(delegate()
@@ -161,16 +165,8 @@ public sealed class BSPrim : PhysicsActor
161 165
162 _scene.TaintedObject(delegate() 166 _scene.TaintedObject(delegate()
163 { 167 {
164 // undo any dependance with/on other objects 168 // Undo any links between me and any other object
165 if (_parentPrim != null) 169 _linkset = _linkset.RemoveMeFromLinkset(this);
166 {
167 // If I'm someone's child, tell them to forget about me.
168 _parentPrim.RemoveChildFromLinkset(this);
169 _parentPrim = null;
170 }
171
172 // make sure there are no other prims linked to me
173 UnlinkAllChildren();
174 170
175 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. 171 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
176 BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); 172 BulletSimAPI.DestroyObject(_scene.WorldID, LocalID);
@@ -187,7 +183,7 @@ public sealed class BSPrim : PhysicsActor
187 _scene.TaintedObject(delegate() 183 _scene.TaintedObject(delegate()
188 { 184 {
189 _mass = CalculateMass(); // changing size changes the mass 185 _mass = CalculateMass(); // changing size changes the mass
190 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, Mass, IsPhysical); 186 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical);
191 RecreateGeomAndObject(); 187 RecreateGeomAndObject();
192 }); 188 });
193 } 189 }
@@ -226,32 +222,8 @@ public sealed class BSPrim : PhysicsActor
226 BSPrim parent = obj as BSPrim; 222 BSPrim parent = obj as BSPrim;
227 DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); 223 DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
228 DetailLog("{0},link,parent={1}", LocalID, obj.LocalID); 224 DetailLog("{0},link,parent={1}", LocalID, obj.LocalID);
229 // TODO: decide if this parent checking needs to happen at taint time 225
230 if (_parentPrim == null) 226 _linkset = _linkset.AddMeToLinkset(this, parent);
231 {
232 if (parent != null)
233 {
234 // I don't have a parent so I am joining a linkset
235 parent.AddChildToLinkset(this);
236 }
237 }
238 else
239 {
240 // I already have a parent, is parenting changing?
241 if (parent != _parentPrim)
242 {
243 if (parent == null)
244 {
245 // we are being removed from a linkset
246 _parentPrim.RemoveChildFromLinkset(this);
247 }
248 else
249 {
250 // asking to reparent a prim should not happen
251 m_log.ErrorFormat("{0}: link(): Reparenting a prim. ", LogHeader);
252 }
253 }
254 }
255 return; 227 return;
256 } 228 }
257 229
@@ -260,81 +232,18 @@ public sealed class BSPrim : PhysicsActor
260 // TODO: decide if this parent checking needs to happen at taint time 232 // TODO: decide if this parent checking needs to happen at taint time
261 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen 233 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
262 DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID, 234 DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
263 (_parentPrim==null ? "NULL" : _parentPrim._avName+"/"+_parentPrim.LocalID.ToString())); 235 _linkset.Root._avName+"/"+_linkset.Root.LocalID.ToString());
264 DetailLog("{0},delink,parent={1}", LocalID, (_parentPrim==null ? "NULL" : _parentPrim.LocalID.ToString())); 236 DetailLog("{0},delink,parent={1}", LocalID, _linkset.Root.LocalID.ToString());
265 if (_parentPrim != null)
266 {
267 _parentPrim.RemoveChildFromLinkset(this);
268 }
269 return;
270 }
271 237
272 // I am the root of a linkset and a new child is being added 238 _linkset.RemoveMeFromLinkset(this);
273 public void AddChildToLinkset(BSPrim pchild) 239 return;
274 {
275 BSPrim child = pchild;
276 _scene.TaintedObject(delegate()
277 {
278 if (!_childrenPrims.Contains(child))
279 {
280 DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, this.LocalID);
281 DetailLog("{0},AddChildToLinkset,child={1}", LocalID, pchild.LocalID);
282 _childrenPrims.Add(child);
283 child._parentPrim = this; // the child has gained a parent
284 // RecreateGeomAndObject(); // rebuild my shape with the new child added
285 LinkAChildToMe(pchild); // build the physical binding between me and the child
286
287 _mass = CalculateMass();
288 }
289 });
290 return;
291 }
292
293 // I am the root of a linkset and one of my children is being removed.
294 // Safe to call even if the child is not really in my linkset.
295 public void RemoveChildFromLinkset(BSPrim pchild)
296 {
297 BSPrim child = pchild;
298 _scene.TaintedObject(delegate()
299 {
300 if (_childrenPrims.Contains(child))
301 {
302 DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
303 DetailLog("{0},RemoveChildFromLinkset,child={1}", LocalID, pchild.LocalID);
304 _childrenPrims.Remove(child);
305 child._parentPrim = null; // the child has lost its parent
306 if (_childrenPrims.Count == 0)
307 {
308 // if the linkset is empty, make sure all linkages have been removed
309 UnlinkAllChildren();
310 }
311 else
312 {
313 // RecreateGeomAndObject(); // rebuild my shape with the child removed
314 UnlinkAChildFromMe(pchild);
315 }
316
317 _mass = CalculateMass();
318 }
319 else
320 {
321 m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset");
322 }
323 });
324 return;
325 }
326
327 // return true if we are the root of a linkset (there are children to manage)
328 public bool IsRootOfLinkset
329 {
330 get { return (_parentPrim == null && _childrenPrims.Count != 0); }
331 } 240 }
332 241
333 // Set motion values to zero. 242 // Set motion values to zero.
334 // Do it to the properties so the values get set in the physics engine. 243 // Do it to the properties so the values get set in the physics engine.
335 // Push the setting of the values to the viewer. 244 // Push the setting of the values to the viewer.
336 // Called at taint time! 245 // Called at taint time!
337 private void ZeroMotion() 246 public void ZeroMotion()
338 { 247 {
339 _velocity = OMV.Vector3.Zero; 248 _velocity = OMV.Vector3.Zero;
340 _acceleration = OMV.Vector3.Zero; 249 _acceleration = OMV.Vector3.Zero;
@@ -355,9 +264,10 @@ public sealed class BSPrim : PhysicsActor
355 264
356 public override OMV.Vector3 Position { 265 public override OMV.Vector3 Position {
357 get { 266 get {
358 // child prims move around based on their parent. Need to get the latest location 267 if (!_linkset.IsRoot(this))
359 if (_parentPrim != null) 268 // child prims move around based on their parent. Need to get the latest location
360 _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 269 _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
270
361 // don't do the GetObjectPosition for root elements because this function is called a zillion times 271 // don't do the GetObjectPosition for root elements because this function is called a zillion times
362 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 272 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
363 return _position; 273 return _position;
@@ -373,16 +283,31 @@ public sealed class BSPrim : PhysicsActor
373 } 283 }
374 } 284 }
375 285
376 // Return the effective mass of the object. Non-physical objects do not have mass. 286 // Return the effective mass of the object.
377 public override float Mass { 287 // If there are multiple items in the linkset, add them together for the root
378 get { 288 public override float Mass
379 if (IsPhysical) 289 {
380 return _mass; 290 get
381 else 291 {
382 return 0f; 292 return _linkset.LinksetMass;
383 } 293 }
384 } 294 }
385 295
296 // used when we only want this prim's mass and not the linkset thing
297 public float MassRaw { get { return _mass; } }
298
299 // Is this used?
300 public override OMV.Vector3 CenterOfMass
301 {
302 get { return _linkset.CenterOfMass; }
303 }
304
305 // Is this used?
306 public override OMV.Vector3 GeometricCenter
307 {
308 get { return _linkset.GeometricCenter; }
309 }
310
386 public override OMV.Vector3 Force { 311 public override OMV.Vector3 Force {
387 get { return _force; } 312 get { return _force; }
388 set { 313 set {
@@ -473,8 +398,6 @@ public sealed class BSPrim : PhysicsActor
473 return; 398 return;
474 } 399 }
475 400
476 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
477 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
478 public override OMV.Vector3 Velocity { 401 public override OMV.Vector3 Velocity {
479 get { return _velocity; } 402 get { return _velocity; }
480 set { 403 set {
@@ -503,9 +426,9 @@ public sealed class BSPrim : PhysicsActor
503 } 426 }
504 public override OMV.Quaternion Orientation { 427 public override OMV.Quaternion Orientation {
505 get { 428 get {
506 if (_parentPrim != null) 429 if (!_linkset.IsRoot(this))
507 { 430 {
508 // children move around because tied to parent. Get a fresh value. 431 // Children move around because tied to parent. Get a fresh value.
509 _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID); 432 _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID);
510 } 433 }
511 return _orientation; 434 return _orientation;
@@ -555,14 +478,16 @@ public sealed class BSPrim : PhysicsActor
555 private void SetObjectDynamic() 478 private void SetObjectDynamic()
556 { 479 {
557 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid); 480 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid);
558 // non-physical things work best with a mass of zero 481
559 if (!IsStatic) 482 RecreateGeomAndObject();
560 { 483
561 _mass = CalculateMass(); 484 float mass = _mass;
562 RecreateGeomAndObject(); 485 // Bullet wants static objects have a mass of zero
563 } 486 if (IsStatic)
564 DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, Mass); 487 mass = 0f;
565 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), Mass); 488
489 DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, mass);
490 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
566 } 491 }
567 492
568 // prims don't fly 493 // prims don't fly
@@ -1004,6 +929,9 @@ public sealed class BSPrim : PhysicsActor
1004 929
1005 returnMass = _density * volume; 930 returnMass = _density * volume;
1006 931
932 /*
933 * This change means each object keeps its own mass and the Mass property
934 * will return the sum if we're part of a linkset.
1007 if (IsRootOfLinkset) 935 if (IsRootOfLinkset)
1008 { 936 {
1009 foreach (BSPrim prim in _childrenPrims) 937 foreach (BSPrim prim in _childrenPrims)
@@ -1011,6 +939,7 @@ public sealed class BSPrim : PhysicsActor
1011 returnMass += prim.CalculateMass(); 939 returnMass += prim.CalculateMass();
1012 } 940 }
1013 } 941 }
942 */
1014 943
1015 if (returnMass <= 0) 944 if (returnMass <= 0)
1016 returnMass = 0.0001f; 945 returnMass = 0.0001f;
@@ -1026,9 +955,11 @@ public sealed class BSPrim : PhysicsActor
1026 // The objects needs a hull if it's physical otherwise a mesh is enough 955 // The objects needs a hull if it's physical otherwise a mesh is enough
1027 // No locking here because this is done when we know physics is not simulating 956 // No locking here because this is done when we know physics is not simulating
1028 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used 957 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used
1029 private void CreateGeom(bool forceRebuild) 958 // Returns 'true' if the geometry was rebuilt
959 private bool CreateGeom(bool forceRebuild)
1030 { 960 {
1031 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. 961 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
962 bool ret = false;
1032 if (!_scene.NeedsMeshing(_pbs)) 963 if (!_scene.NeedsMeshing(_pbs))
1033 { 964 {
1034 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) 965 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
@@ -1036,18 +967,26 @@ public sealed class BSPrim : PhysicsActor
1036 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) 967 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
1037 { 968 {
1038 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); 969 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
1039 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; 970 if (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE)
1040 DetailLog("{0},CreateGeom,sphere", LocalID); 971 {
1041 // Bullet native objects are scaled by the Bullet engine so pass the size in 972 DetailLog("{0},CreateGeom,sphere", LocalID);
1042 _scale = _size; 973 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
974 ret = true;
975 // Bullet native objects are scaled by the Bullet engine so pass the size in
976 _scale = _size;
977 }
1043 } 978 }
1044 } 979 }
1045 else 980 else
1046 { 981 {
1047 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); 982 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size);
1048 DetailLog("{0},CreateGeom,box", LocalID); 983 if (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX)
1049 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; 984 {
1050 _scale = _size; 985 DetailLog("{0},CreateGeom,box", LocalID);
986 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
987 ret = true;
988 _scale = _size;
989 }
1051 } 990 }
1052 } 991 }
1053 else 992 else
@@ -1059,6 +998,7 @@ public sealed class BSPrim : PhysicsActor
1059 // physical objects require a hull for interaction. 998 // physical objects require a hull for interaction.
1060 // This will create the mesh if it doesn't already exist 999 // This will create the mesh if it doesn't already exist
1061 CreateGeomHull(); 1000 CreateGeomHull();
1001 ret = true;
1062 } 1002 }
1063 } 1003 }
1064 else 1004 else
@@ -1067,9 +1007,11 @@ public sealed class BSPrim : PhysicsActor
1067 { 1007 {
1068 // Static (non-physical) objects only need a mesh for bumping into 1008 // Static (non-physical) objects only need a mesh for bumping into
1069 CreateGeomMesh(); 1009 CreateGeomMesh();
1010 ret = true;
1070 } 1011 }
1071 } 1012 }
1072 } 1013 }
1014 return ret;
1073 } 1015 }
1074 1016
1075 // No locking here because this is done when we know physics is not simulating 1017 // No locking here because this is done when we know physics is not simulating
@@ -1254,20 +1196,18 @@ public sealed class BSPrim : PhysicsActor
1254 // No locking here because this is done when the physics engine is not simulating 1196 // No locking here because this is done when the physics engine is not simulating
1255 private void CreateObject() 1197 private void CreateObject()
1256 { 1198 {
1257 if (IsRootOfLinkset) 1199 // this routine is called when objects are rebuilt.
1258 { 1200
1259 // Create a linkset around this object 1201 // the mesh or hull must have already been created in Bullet
1260 CreateLinkset(); 1202 ShapeData shape;
1261 } 1203 FillShapeInfo(out shape);
1262 else 1204 // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
1263 { 1205 BulletSimAPI.CreateObject(_scene.WorldID, shape);
1264 // simple object 1206 // the CreateObject() may have recreated the rigid body. Make sure we have the latest.
1265 // the mesh or hull must have already been created in Bullet 1207 m_body.Ptr = BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID);
1266 ShapeData shape; 1208
1267 FillShapeInfo(out shape); 1209 // The root object could have been recreated. Make sure everything linksety is up to date.
1268 // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type); 1210 _linkset.RefreshLinkset(this);
1269 BulletSimAPI.CreateObject(_scene.WorldID, shape);
1270 }
1271 } 1211 }
1272 1212
1273 // Copy prim's info into the BulletSim shape description structure 1213 // Copy prim's info into the BulletSim shape description structure
@@ -1279,7 +1219,7 @@ public sealed class BSPrim : PhysicsActor
1279 shape.Rotation = _orientation; 1219 shape.Rotation = _orientation;
1280 shape.Velocity = _velocity; 1220 shape.Velocity = _velocity;
1281 shape.Scale = _scale; 1221 shape.Scale = _scale;
1282 shape.Mass = Mass; 1222 shape.Mass = _isPhysical ? _mass : 0f;
1283 shape.Buoyancy = _buoyancy; 1223 shape.Buoyancy = _buoyancy;
1284 shape.HullKey = _hullKey; 1224 shape.HullKey = _hullKey;
1285 shape.MeshKey = _meshKey; 1225 shape.MeshKey = _meshKey;
@@ -1289,83 +1229,6 @@ public sealed class BSPrim : PhysicsActor
1289 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; 1229 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1290 } 1230 }
1291 1231
1292 #region Linkset creation and destruction
1293
1294 // Create the linkset by putting constraints between the objects of the set so they cannot move
1295 // relative to each other.
1296 void CreateLinkset()
1297 {
1298 // DebugLog("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
1299
1300 // remove any constraints that might be in place
1301 UnlinkAllChildren();
1302
1303 // create constraints between the root prim and each of the children
1304 foreach (BSPrim prim in _childrenPrims)
1305 {
1306 LinkAChildToMe(prim);
1307 }
1308 }
1309
1310 // Create a constraint between me (root of linkset) and the passed prim (the child).
1311 // Called at taint time!
1312 private void LinkAChildToMe(BSPrim childPrim)
1313 {
1314 // Zero motion for children so they don't interpolate
1315 childPrim.ZeroMotion();
1316
1317 // relative position normalized to the root prim
1318 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(this._orientation);
1319 OMV.Vector3 childRelativePosition = (childPrim._position - this._position) * invThisOrientation;
1320
1321 // relative rotation of the child to the parent
1322 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim._orientation;
1323
1324 // create a constraint that allows no freedom of movement between the two objects
1325 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
1326 // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
1327 DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", LocalID, LocalID, childPrim.LocalID);
1328 BSConstraint constrain = _scene.Constraints.CreateConstraint(
1329 _scene.World, this.Body, childPrim.Body,
1330 childRelativePosition,
1331 childRelativeRotation,
1332 OMV.Vector3.Zero,
1333 OMV.Quaternion.Identity);
1334 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
1335 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
1336
1337 // tweek the constraint to increase stability
1338 constrain.UseFrameOffset(_scene.BoolNumeric(_scene.Params.linkConstraintUseFrameOffset));
1339 if (_scene.BoolNumeric(_scene.Params.linkConstraintEnableTransMotor))
1340 {
1341 constrain.TranslationalLimitMotor(true,
1342 _scene.Params.linkConstraintTransMotorMaxVel,
1343 _scene.Params.linkConstraintTransMotorMaxForce);
1344 }
1345 }
1346
1347 // Remove linkage between myself and a particular child
1348 // Called at taint time!
1349 private void UnlinkAChildFromMe(BSPrim childPrim)
1350 {
1351 DebugLog("{0}: UnlinkAChildFromMe: RemoveConstraint between root prim {1} and child prim {2}",
1352 LogHeader, LocalID, childPrim.LocalID);
1353 DetailLog("{0},UnlinkAChildFromMe,taint,root={1},child={2}", LocalID, LocalID, childPrim.LocalID);
1354 // BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID);
1355 _scene.Constraints.RemoveAndDestroyConstraint(this.Body, childPrim.Body);
1356 }
1357
1358 // Remove linkage between myself and any possible children I might have
1359 // Called at taint time!
1360 private void UnlinkAllChildren()
1361 {
1362 DebugLog("{0}: UnlinkAllChildren:", LogHeader);
1363 DetailLog("{0},UnlinkAllChildren,taint", LocalID);
1364 _scene.Constraints.RemoveAndDestroyConstraint(this.Body);
1365 // BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID);
1366 }
1367
1368 #endregion // Linkset creation and destruction
1369 1232
1370 // Rebuild the geometry and object. 1233 // Rebuild the geometry and object.
1371 // This is called when the shape changes so we need to recreate the mesh/hull. 1234 // This is called when the shape changes so we need to recreate the mesh/hull.
@@ -1443,7 +1306,7 @@ public sealed class BSPrim : PhysicsActor
1443 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1306 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1444 1307
1445 // Updates only for individual prims and for the root object of a linkset. 1308 // Updates only for individual prims and for the root object of a linkset.
1446 if (_parentPrim == null) 1309 if (_linkset.IsRoot(this))
1447 { 1310 {
1448 // Assign to the local variables so the normal set action does not happen 1311 // Assign to the local variables so the normal set action does not happen
1449 _position = entprop.Position; 1312 _position = entprop.Position;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index a1587a8..c6d622b 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -73,7 +73,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
74 private static readonly string LogHeader = "[BULLETS SCENE]"; 74 private static readonly string LogHeader = "[BULLETS SCENE]";
75 75
76 private void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); } 76 public void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); }
77 77
78 public string BulletSimVersion = "?"; 78 public string BulletSimVersion = "?";
79 79
@@ -87,6 +87,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
87 private uint m_worldID; 87 private uint m_worldID;
88 public uint WorldID { get { return m_worldID; } } 88 public uint WorldID { get { return m_worldID; } }
89 89
90 // let my minuions use my logger
91 public ILog Logger { get { return m_log; } }
92
90 private bool m_initialized = false; 93 private bool m_initialized = false;
91 94
92 private int m_detailedStatsStep = 0; 95 private int m_detailedStatsStep = 0;
@@ -1026,7 +1029,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1026 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), 1029 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
1027 1030
1028 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", 1031 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
1029 ConfigurationParameters.numericTrue, 1032 ConfigurationParameters.numericFalse,
1030 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1033 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1031 (s) => { return s.m_params[0].linkConstraintUseFrameOffset; }, 1034 (s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
1032 (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ), 1035 (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 89fd9b7..65e3145 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -239,10 +239,10 @@ public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
239[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 239[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
240public static extern bool CreateObject(uint worldID, ShapeData shapeData); 240public static extern bool CreateObject(uint worldID, ShapeData shapeData);
241 241
242/* Remove old functionality
242[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 243[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
243public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas); 244public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
244 245
245/* Remove old functionality
246[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 246[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
247public static extern void AddConstraint(uint worldID, uint id1, uint id2, 247public static extern void AddConstraint(uint worldID, uint id1, uint id2,
248 Vector3 frame1, Quaternion frame1rot, 248 Vector3 frame1, Quaternion frame1rot,
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index 32e81e2..0db936f 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -489,6 +489,8 @@ namespace OpenSim.Region.Physics.OdePlugin
489 /// </summary> 489 /// </summary>
490 internal Object OdeLock = new Object(); 490 internal Object OdeLock = new Object();
491 491
492 private bool _worldInitialized = false;
493
492 public IMesher mesher; 494 public IMesher mesher;
493 495
494 private IConfigSource m_config; 496 private IConfigSource m_config;
@@ -875,6 +877,8 @@ namespace OpenSim.Region.Physics.OdePlugin
875 staticPrimspace[i, j] = IntPtr.Zero; 877 staticPrimspace[i, j] = IntPtr.Zero;
876 } 878 }
877 } 879 }
880
881 _worldInitialized = true;
878 } 882 }
879 883
880// internal void waitForSpaceUnlock(IntPtr space) 884// internal void waitForSpaceUnlock(IntPtr space)
@@ -2896,6 +2900,8 @@ namespace OpenSim.Region.Physics.OdePlugin
2896 /// <returns>The number of frames simulated over that period.</returns> 2900 /// <returns>The number of frames simulated over that period.</returns>
2897 public override float Simulate(float timeStep) 2901 public override float Simulate(float timeStep)
2898 { 2902 {
2903 if (!_worldInitialized) return 11f;
2904
2899 int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0; 2905 int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0;
2900 int tempTick = 0, tempTick2 = 0; 2906 int tempTick = 0, tempTick2 = 0;
2901 2907
@@ -4017,6 +4023,8 @@ namespace OpenSim.Region.Physics.OdePlugin
4017 4023
4018 public override void Dispose() 4024 public override void Dispose()
4019 { 4025 {
4026 _worldInitialized = false;
4027
4020 m_rayCastManager.Dispose(); 4028 m_rayCastManager.Dispose();
4021 m_rayCastManager = null; 4029 m_rayCastManager = null;
4022 4030
@@ -4037,6 +4045,7 @@ namespace OpenSim.Region.Physics.OdePlugin
4037 d.WorldDestroy(world); 4045 d.WorldDestroy(world);
4038 //d.CloseODE(); 4046 //d.CloseODE();
4039 } 4047 }
4048
4040 } 4049 }
4041 4050
4042 public override Dictionary<uint, float> GetTopColliders() 4051 public override Dictionary<uint, float> GetTopColliders()