aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSScene.cs329
1 files changed, 235 insertions, 94 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
index 452ce55..163efaa 100644
--- a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
@@ -124,9 +124,10 @@ namespace OpenSim.Region.PhysicsModule.BulletS
124 // True if initialized and ready to do simulation steps 124 // True if initialized and ready to do simulation steps
125 private bool m_initialized = false; 125 private bool m_initialized = false;
126 126
127 // Flag which is true when processing taints. 127 // Object locked whenever execution is inside the physics engine
128 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging. 128 public Object PhysicsEngineLock = new object();
129 public bool InTaintTime { get; private set; } 129 // Flag that is true when the simulator is active and shouldn't be touched
130 public bool InSimulationTime { get; private set; }
130 131
131 // Pinned memory used to pass step information between managed and unmanaged 132 // Pinned memory used to pass step information between managed and unmanaged
132 internal int m_maxCollisionsPerFrame; 133 internal int m_maxCollisionsPerFrame;
@@ -212,6 +213,11 @@ namespace OpenSim.Region.PhysicsModule.BulletS
212 get { return "BulletSim"; } 213 get { return "BulletSim"; }
213 } 214 }
214 215
216 public string Version
217 {
218 get { return "1.0"; }
219 }
220
215 public Type ReplaceableInterface 221 public Type ReplaceableInterface
216 { 222 {
217 get { return null; } 223 get { return null; }
@@ -245,6 +251,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
245 EngineType = Name; 251 EngineType = Name;
246 RegionName = scene.RegionInfo.RegionName; 252 RegionName = scene.RegionInfo.RegionName;
247 PhysicsSceneName = EngineType + "/" + RegionName; 253 PhysicsSceneName = EngineType + "/" + RegionName;
254 EngineName = Name + " " + Version;
248 255
249 scene.RegisterModuleInterface<PhysicsScene>(this); 256 scene.RegisterModuleInterface<PhysicsScene>(this);
250 Vector3 extent = new Vector3(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, scene.RegionInfo.RegionSizeZ); 257 Vector3 extent = new Vector3(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, scene.RegionInfo.RegionSizeZ);
@@ -338,19 +345,19 @@ namespace OpenSim.Region.PhysicsModule.BulletS
338 // Put some informational messages into the log file. 345 // Put some informational messages into the log file.
339 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); 346 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
340 347
341 InTaintTime = false; 348 InSimulationTime = false;
342 m_initialized = true; 349 m_initialized = true;
343 350
344 // If the physics engine runs on its own thread, start same. 351 // If the physics engine runs on its own thread, start same.
345 if (BSParam.UseSeparatePhysicsThread) 352 if (BSParam.UseSeparatePhysicsThread)
346 { 353 {
347 // The physics simulation should happen independently of the heartbeat loop 354 // The physics simulation should happen independently of the heartbeat loop
348 m_physicsThread 355 m_physicsThread
349 = WorkManager.StartThread( 356 = WorkManager.StartThread(
350 BulletSPluginPhysicsThread, 357 BulletSPluginPhysicsThread,
351 string.Format("{0} ({1})", BulletEngineName, RegionName), 358 string.Format("{0} ({1})", BulletEngineName, RegionName),
352 ThreadPriority.Normal, 359 ThreadPriority.Normal,
353 true, 360 true,
354 true); 361 true);
355 } 362 }
356 } 363 }
@@ -523,13 +530,13 @@ namespace OpenSim.Region.PhysicsModule.BulletS
523 return null; 530 return null;
524 } 531 }
525 532
526 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) 533 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, float footOffset, bool isFlying)
527 { 534 {
528 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName); 535 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
529 536
530 if (!m_initialized) return null; 537 if (!m_initialized) return null;
531 538
532 BSCharacter actor = new BSCharacter(localID, avName, this, position, velocity, size, isFlying); 539 BSCharacter actor = new BSCharacter(localID, avName, this, position, Vector3.Zero, size, footOffset, isFlying);
533 lock (PhysObjects) 540 lock (PhysObjects)
534 PhysObjects.Add(localID, actor); 541 PhysObjects.Add(localID, actor);
535 542
@@ -651,49 +658,57 @@ namespace OpenSim.Region.PhysicsModule.BulletS
651 658
652 int beforeTime = Util.EnvironmentTickCount(); 659 int beforeTime = Util.EnvironmentTickCount();
653 int simTime = 0; 660 int simTime = 0;
661 int numTaints = 0;
662 int numSubSteps = 0;
654 663
655 int numTaints = _taintOperations.Count; 664 lock (PhysicsEngineLock)
656 InTaintTime = true; // Only used for debugging so locking is not necessary. 665 {
666 InSimulationTime = true;
667 // update the prim states while we know the physics engine is not busy
668 numTaints += ProcessTaints();
657 669
658 // update the prim states while we know the physics engine is not busy 670 // Some of the physical objects requre individual, pre-step calls
659 ProcessTaints(); 671 // (vehicles and avatar movement, in particular)
672 TriggerPreStepEvent(timeStep);
660 673
661 // Some of the physical objects requre individual, pre-step calls 674 // the prestep actions might have added taints
662 // (vehicles and avatar movement, in particular) 675 numTaints += ProcessTaints();
663 TriggerPreStepEvent(timeStep);
664 676
665 // the prestep actions might have added taints 677 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
666 numTaints += _taintOperations.Count; 678 // Only enable this in a limited test world with few objects.
667 ProcessTaints(); 679 if (m_physicsPhysicalDumpEnabled)
680 PE.DumpAllInfo(World);
668 681
669 InTaintTime = false; // Only used for debugging so locking is not necessary. 682 // step the physical world one interval
683 m_simulationStep++;
684 try
685 {
686 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
687 }
688 catch (Exception e)
689 {
690 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
691 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
692 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
693 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
694 updatedEntityCount = 0;
695 collidersCount = 0;
696 }
670 697
671 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. 698 // Make the physics engine dump useful statistics periodically
672 // Only enable this in a limited test world with few objects. 699 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
673 if (m_physicsPhysicalDumpEnabled) 700 PE.DumpPhysicsStatistics(World);
674 PE.DumpAllInfo(World);
675 701
676 // step the physical world one interval 702 InSimulationTime = false;
677 m_simulationStep++;
678 int numSubSteps = 0;
679 try
680 {
681 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
682 703
683 } 704 // Some actors want to know when the simulation step is complete.
684 catch (Exception e) 705 TriggerPostStepEvent(timeStep);
685 { 706
686 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", 707 // In case there were any parameter updates that happened during the simulation step
687 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); 708 numTaints += ProcessTaints();
688 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
689 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
690 updatedEntityCount = 0;
691 collidersCount = 0;
692 }
693 709
694 // Make the physics engine dump useful statistics periodically 710 InSimulationTime = false;
695 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) 711 }
696 PE.DumpPhysicsStatistics(World);
697 712
698 // Get a value for 'now' so all the collision and update routines don't have to get their own. 713 // Get a value for 'now' so all the collision and update routines don't have to get their own.
699 SimulationNowTime = Util.EnvironmentTickCount(); 714 SimulationNowTime = Util.EnvironmentTickCount();
@@ -743,9 +758,6 @@ namespace OpenSim.Region.PhysicsModule.BulletS
743 } 758 }
744 } 759 }
745 760
746 // Some actors want to know when the simulation step is complete.
747 TriggerPostStepEvent(timeStep);
748
749 simTime = Util.EnvironmentTickCountSubtract(beforeTime); 761 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
750 if (PhysicsLogging.Enabled) 762 if (PhysicsLogging.Enabled)
751 { 763 {
@@ -762,7 +774,8 @@ namespace OpenSim.Region.PhysicsModule.BulletS
762 // The physics engine returns the number of milliseconds it simulated this call. 774 // The physics engine returns the number of milliseconds it simulated this call.
763 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 775 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
764 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). 776 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
765 m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; 777// m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
778 m_simulatedTime += (float)numSubSteps * m_fixedTimeStep;
766 } 779 }
767 780
768 // Called by a BSPhysObject to note that it has changed properties and this information 781 // Called by a BSPhysObject to note that it has changed properties and this information
@@ -849,7 +862,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
849 862
850 // Return the framerate simulated to give the above returned results. 863 // Return the framerate simulated to give the above returned results.
851 // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock). 864 // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock).
852 float simTime = m_simulatedTime; 865 float simTime = m_simulatedTime / timeStep;
853 m_simulatedTime = 0f; 866 m_simulatedTime = 0f;
854 return simTime; 867 return simTime;
855 } 868 }
@@ -879,7 +892,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
879 892
880 if (collider.IsInitialized) 893 if (collider.IsInitialized)
881 { 894 {
882 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) 895 if (collider.Collide(collidee, collidePoint, collideNormal, penetration))
883 { 896 {
884 // If a collision was 'good', remember to send it to the simulator 897 // If a collision was 'good', remember to send it to the simulator
885 lock (CollisionLock) 898 lock (CollisionLock)
@@ -948,26 +961,150 @@ namespace OpenSim.Region.PhysicsModule.BulletS
948 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); 961 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
949 } 962 }
950 963
951 // Although no one seems to check this, I do support combining. 964 #endregion // Terrain
952 public override bool SupportsCombining() 965
966 #region Raycast
967
968 public override bool SupportsRayCast()
953 { 969 {
954 return TerrainManager.SupportsCombining(); 970 return BSParam.UseBulletRaycast;
955 } 971 }
956 // This call says I am a child to region zero in a mega-region. 'pScene' is that 972
957 // of region zero, 'offset' is my offset from regions zero's origin, and 973 public override bool SupportsRaycastWorldFiltered()
958 // 'extents' is the largest XY that is handled in my region.
959 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
960 { 974 {
961 TerrainManager.Combine(pScene, offset, extents); 975 return BSParam.UseBulletRaycast;
962 } 976 }
963 977
964 // Unhook all the combining that I know about. 978
965 public override void UnCombine(PhysicsScene pScene) 979 /// <summary>
980 /// Queue a raycast against the physics scene.
981 /// The provided callback method will be called when the raycast is complete
982 ///
983 /// Many physics engines don't support collision testing at the same time as
984 /// manipulating the physics scene, so we queue the request up and callback
985 /// a custom method when the raycast is complete.
986 /// This allows physics engines that give an immediate result to callback immediately
987 /// and ones that don't, to callback when it gets a result back.
988 /// public delegate void RayCallback(List<ContactResult> list);
989 ///
990 /// ODE for example will not allow you to change the scene while collision testing or
991 /// it asserts, 'opteration not valid for locked space'. This includes adding a ray to the scene.
992 ///
993 /// This is named RayCastWorld to not conflict with modrex's Raycast method.
994 /// </summary>
995 /// <param name="position">Origin of the ray</param>
996 /// <param name="direction">Direction of the ray</param>
997 /// <param name="length">Length of ray in meters</param>
998 /// <param name="retMethod">Method to call when the raycast is complete</param>
999 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
966 { 1000 {
967 TerrainManager.UnCombine(pScene); 1001 if (retMethod != null)
1002 {
1003 if (BSParam.UseBulletRaycast)
1004 {
1005 Vector3 posFrom = position;
1006 Vector3 posTo = Vector3.Normalize(direction) * length + position;
1007
1008 TaintedObject(DetailLogZero, "BSScene.RaycastWorld1", delegate ()
1009 {
1010 RaycastHit hitInfo = PE.RayTest2(World, posFrom, posTo, 0xffff, 0xffff);
1011 retMethod(true, hitInfo.Point, hitInfo.ID, hitInfo.Fraction, hitInfo.Normal);
1012 });
1013 }
1014 else
1015 {
1016 retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero);
1017 }
1018 }
968 } 1019 }
969 1020
970 #endregion // Terrain 1021 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod)
1022 {
1023 if (retMethod != null)
1024 {
1025 if (BSParam.UseBulletRaycast)
1026 {
1027 List<ContactResult> hitInfo = RaycastWorld(position, direction, length, count);
1028 retMethod(hitInfo);
1029 }
1030 else
1031 {
1032 retMethod(new List<ContactResult>());
1033 }
1034 }
1035 }
1036
1037 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int count)
1038 {
1039 return (List<ContactResult>)RaycastWorld(position, direction, length, count, RayFilterFlags.All);
1040 }
1041
1042 public override object RaycastWorld(Vector3 position, Vector3 direction, float length, int count, RayFilterFlags filter)
1043 {
1044 List<ContactResult> ret = new List<ContactResult>();
1045 if (BSParam.UseBulletRaycast)
1046 {
1047 uint collisionFilter = 0;
1048 uint collisionMask = 0;
1049 if ((filter & RayFilterFlags.land) != 0)
1050 {
1051 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Terrain].group;
1052 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Terrain].mask;
1053 }
1054 if ((filter & RayFilterFlags.agent) != 0)
1055 {
1056 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Avatar].group;
1057 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Avatar].mask;
1058 }
1059 if ((filter & RayFilterFlags.nonphysical) != 0)
1060 {
1061 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Static].group;
1062 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Static].mask;
1063 }
1064 if ((filter & RayFilterFlags.physical) != 0)
1065 {
1066 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Dynamic].group;
1067 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Dynamic].mask;
1068 }
1069 // if ((filter & RayFilterFlags.phantom) != 0)
1070 // {
1071 // collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].group;
1072 // collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].mask;
1073 // }
1074 if ((filter & RayFilterFlags.volumedtc) != 0)
1075 {
1076 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].group;
1077 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].mask;
1078 }
1079 DetailLog("{0},RaycastWorld,pos={1},dir={2},len={3},count={4},filter={5},filter={6},mask={7}",
1080 DetailLogZero, position, direction, length, count, filter, collisionFilter, collisionMask);
1081 // NOTE: locking ensures the physics engine is not executing.
1082 // The caller might have to wait for the physics engine to finish.
1083 lock (PhysicsEngineLock)
1084 {
1085 Vector3 posFrom = position;
1086 Vector3 posTo = Vector3.Normalize(direction) * length + position;
1087 DetailLog("{0},RaycastWorld,RayTest2,from={1},to={2}",
1088 DetailLogZero, posFrom, posTo);
1089 RaycastHit hitInfo = PE.RayTest2(World, posFrom, posTo, collisionFilter, collisionMask);
1090 if (hitInfo.hasHit())
1091 {
1092 ContactResult result = new ContactResult();
1093 result.Pos = hitInfo.Point;
1094 result.Normal = hitInfo.Normal;
1095 result.ConsumerID = hitInfo.ID;
1096 result.Depth = hitInfo.Fraction;
1097 ret.Add(result);
1098 DetailLog("{0},RaycastWorld,hit,pos={1},norm={2},depth={3},id={4}",
1099 DetailLogZero, result.Pos, result.Normal, result.Depth, result.ConsumerID);
1100 }
1101 }
1102 }
1103 return ret;
1104 }
1105
1106 #endregion Raycast
1107
971 1108
972 public override Dictionary<uint, float> GetTopColliders() 1109 public override Dictionary<uint, float> GetTopColliders()
973 { 1110 {
@@ -1081,32 +1218,35 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1081 // Calls to the PhysicsActors can't directly call into the physics engine 1218 // Calls to the PhysicsActors can't directly call into the physics engine
1082 // because it might be busy. We delay changes to a known time. 1219 // because it might be busy. We delay changes to a known time.
1083 // We rely on C#'s closure to save and restore the context for the delegate. 1220 // We rely on C#'s closure to save and restore the context for the delegate.
1084 public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback) 1221 // NOTE: 'inTaintTime' is no longer used. This entry exists so all the calls don't have to be changed.
1222 // public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
1223 // {
1224 // TaintedObject(BSScene.DetailLogZero, pIdent, pCallback);
1225 // }
1226 // NOTE: 'inTaintTime' is no longer used. This entry exists so all the calls don't have to be changed.
1227 public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
1085 { 1228 {
1086 TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback); 1229 TaintedObject(m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1087 } 1230 }
1088 public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback) 1231 public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback)
1089 { 1232 {
1090 TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback); 1233 TaintedObject(m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1091 }
1092 public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
1093 {
1094 TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback);
1095 }
1096 public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
1097 {
1098 TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1099 } 1234 }
1100 // Sometimes a potentially tainted operation can be used in and out of taint time. 1235 // Sometimes a potentially tainted operation can be used in and out of taint time.
1101 // This routine executes the command immediately if in taint-time otherwise it is queued. 1236 // This routine executes the command immediately if in taint-time otherwise it is queued.
1102 public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback) 1237 public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback)
1103 { 1238 {
1104 if (!m_initialized) return; 1239 if (!m_initialized) return;
1105 1240
1106 if (inTaintTime) 1241 if (Monitor.TryEnter(PhysicsEngineLock))
1242 {
1243 // If we can get exclusive access to the physics engine, just do the operation
1107 pCallback(); 1244 pCallback();
1245 Monitor.Exit(PhysicsEngineLock);
1246 }
1108 else 1247 else
1109 { 1248 {
1249 // The physics engine is busy, queue the operation
1110 lock (_taintLock) 1250 lock (_taintLock)
1111 { 1251 {
1112 _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback)); 1252 _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback));
@@ -1133,14 +1273,21 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1133 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues 1273 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
1134 // a callback into itself to do the actual property change. That callback is called 1274 // a callback into itself to do the actual property change. That callback is called
1135 // here just before the physics engine is called to step the simulation. 1275 // here just before the physics engine is called to step the simulation.
1136 public void ProcessTaints() 1276 // Returns the number of taints processed
1277 // NOTE: Called while PhysicsEngineLock is locked
1278 public int ProcessTaints()
1137 { 1279 {
1138 ProcessRegularTaints(); 1280 int ret = 0;
1139 ProcessPostTaintTaints(); 1281 ret += ProcessRegularTaints();
1282 ret += ProcessPostTaintTaints();
1283 return ret;
1140 } 1284 }
1141 1285
1142 private void ProcessRegularTaints() 1286 // Returns the number of taints processed
1287 // NOTE: Called while PhysicsEngineLock is locked
1288 private int ProcessRegularTaints()
1143 { 1289 {
1290 int ret = 0;
1144 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process 1291 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process
1145 { 1292 {
1146 // swizzle a new list into the list location so we can process what's there 1293 // swizzle a new list into the list location so we can process what's there
@@ -1157,6 +1304,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1157 { 1304 {
1158 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG 1305 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG
1159 tcbe.callback(); 1306 tcbe.callback();
1307 ret++;
1160 } 1308 }
1161 catch (Exception e) 1309 catch (Exception e)
1162 { 1310 {
@@ -1165,6 +1313,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1165 } 1313 }
1166 oldList.Clear(); 1314 oldList.Clear();
1167 } 1315 }
1316 return ret;
1168 } 1317 }
1169 1318
1170 // Schedule an update to happen after all the regular taints are processed. 1319 // Schedule an update to happen after all the regular taints are processed.
@@ -1183,8 +1332,11 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1183 } 1332 }
1184 1333
1185 // Taints that happen after the normal taint processing but before the simulation step. 1334 // Taints that happen after the normal taint processing but before the simulation step.
1186 private void ProcessPostTaintTaints() 1335 // Returns the number of taints processed
1336 // NOTE: Called while PhysicsEngineLock is locked
1337 private int ProcessPostTaintTaints()
1187 { 1338 {
1339 int ret = 0;
1188 if (m_initialized && _postTaintOperations.Count > 0) 1340 if (m_initialized && _postTaintOperations.Count > 0)
1189 { 1341 {
1190 Dictionary<string, TaintCallbackEntry> oldList; 1342 Dictionary<string, TaintCallbackEntry> oldList;
@@ -1200,6 +1352,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1200 { 1352 {
1201 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG 1353 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
1202 kvp.Value.callback(); 1354 kvp.Value.callback();
1355 ret++;
1203 } 1356 }
1204 catch (Exception e) 1357 catch (Exception e)
1205 { 1358 {
@@ -1208,20 +1361,8 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1208 } 1361 }
1209 oldList.Clear(); 1362 oldList.Clear();
1210 } 1363 }
1364 return ret;
1211 } 1365 }
1212
1213 // Only used for debugging. Does not change state of anything so locking is not necessary.
1214 public bool AssertInTaintTime(string whereFrom)
1215 {
1216 if (!InTaintTime)
1217 {
1218 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
1219 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
1220 // Util.PrintCallStack(DetailLog);
1221 }
1222 return InTaintTime;
1223 }
1224
1225 #endregion // Taints 1366 #endregion // Taints
1226 1367
1227 #region IPhysicsParameters 1368 #region IPhysicsParameters