// Simulate one timestep
public override void Simulate(float timeStep)
{
// prevent simulation until we've been initialized
if (!m_initialized)
{
return;
}
LastTimeStep = timeStep;
int updatedEntityCount = 0;
int collidersCount = 0;
int beforeTime = 0;
// update the prim states while we know the physics engine is not busy
int numTaints = _taintOperations.Count;
InTaintTime = true; // Only used for debugging so locking is not necessary.
beforeTime = Util.EnvironmentTickCount();
ProcessTaints();
// Some of the physical objects requre individual, pre-step calls
// (vehicles and avatar movement, in particular)
TriggerPreStepEvent(timeStep);
// the prestep actions might have added taints
numTaints += _taintOperations.Count;
ProcessTaints();
StatPhysicsTaintTime = Util.EnvironmentTickCountSubtract(beforeTime);
InTaintTime = false; // Only used for debugging so locking is not necessary.
// The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
// Only enable this in a limited test world with few objects.
if (m_physicsPhysicalDumpEnabled)
{
PE.DumpAllInfo(World);
}
// step the physical world one interval
m_simulationStep++;
int numSubSteps = 0;
try
{
beforeTime = Util.EnvironmentTickCount();
numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount,
out collidersCount);
//if (PhysicsLogging.Enabled)
//{
StatContactLoopTime = Util.EnvironmentTickCountSubtract(beforeTime);
DetailLog(
"{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
DetailLogZero, m_simulationStep, numTaints, StatContactLoopTime, numSubSteps,
updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
//}
}
catch (Exception e)
{
MainConsole.Instance.WarnFormat(
"{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
updatedEntityCount = 0;
collidersCount = 0;
}
if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
{
PE.DumpPhysicsStatistics(World);
}
// Get a value for 'now' so all the collision and update routines don't have to get their own.
SimulationNowTime = Util.EnvironmentTickCount();
beforeTime = Util.EnvironmentTickCount();
// If there were collisions, process them by sending the event to the prim.
// Collisions must be processed before updates.
if (collidersCount > 0)
{
for (int ii = 0; ii < collidersCount; ii++)
{
uint cA = m_collisionArray[ii].aID;
uint cB = m_collisionArray[ii].bID;
Vector3 point = m_collisionArray[ii].point;
Vector3 normal = m_collisionArray[ii].normal;
float penetration = m_collisionArray[ii].penetration;
SendCollision(cA, cB, point, normal, penetration);
SendCollision(cB, cA, point, -normal, penetration);
}
}
// The above SendCollision's batch up the collisions on the objects.
// Now push the collisions into the simulator.
if (ObjectsWithCollisions.Count > 0)
{
foreach (BSPhysObject bsp in ObjectsWithCollisions)
{
if (!bsp.SendCollisions())
{
// If the object is done colliding, see that it's removed from the colliding list
ObjectsWithNoMoreCollisions.Add(bsp);
}
}
}
// This is a kludge to get avatar movement updates.
// The simulator expects collisions for avatars even if there are have been no collisions.
// The event updates avatar animations and stuff.
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
foreach (BSPhysObject bsp in m_avatars)
{
if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
{
bsp.SendCollisions();
}
}
// Objects that are done colliding are removed from the ObjectsWithCollisions list.
// Not done above because it is inside an iteration of ObjectWithCollisions.
// This complex collision processing is required to create an empty collision
// event call after all real collisions have happened on an object. This enables
// the simulator to generate the 'collision end' event.
if (ObjectsWithNoMoreCollisions.Count > 0)
{
foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
{
ObjectsWithCollisions.Remove(po);
}
ObjectsWithNoMoreCollisions.Clear();
}
// Done with collisions.
// If any of the objects had updated properties, tell the object it has been changed by the physics engine
if (updatedEntityCount > 0)
{
for (int ii = 0; ii < updatedEntityCount; ii++)
{
EntityProperties entprop = m_updateArray[ii];
BSPhysObject pobj;
if (PhysObjects.TryGetValue(entprop.ID, out pobj))
{
pobj.UpdateProperties(entprop);
}
}
}
StatPhysicsMoveTime = Util.EnvironmentTickCountSubtract(beforeTime);
TriggerPostStepEvent(timeStep);
// The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
// Only enable this in a limited test world with few objects.
if (m_physicsPhysicalDumpEnabled)
{
PE.DumpAllInfo(World);
}
}