diff options
author | UbitUmarov | 2015-10-13 23:01:54 +0100 |
---|---|---|
committer | UbitUmarov | 2015-10-13 23:01:54 +0100 |
commit | 2e2c1a1fcd83397e552c30da24e2f5874a19cec9 (patch) | |
tree | b67ead6aabb6a86e8e7df749096654d1c308bc1b /OpenSim/Region/PhysicsModules | |
parent | rename UbitMeshmerizer class as ubMeshmerizer (diff) | |
download | opensim-SC_OLD-2e2c1a1fcd83397e552c30da24e2f5874a19cec9.zip opensim-SC_OLD-2e2c1a1fcd83397e552c30da24e2f5874a19cec9.tar.gz opensim-SC_OLD-2e2c1a1fcd83397e552c30da24e2f5874a19cec9.tar.bz2 opensim-SC_OLD-2e2c1a1fcd83397e552c30da24e2f5874a19cec9.tar.xz |
change fps and dilation (still something not that usefull). make collisions a bit less explosive.., do changes on own time limited loop and not on simulation loop, ...
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs | 163 |
1 files changed, 77 insertions, 86 deletions
diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs b/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs index f51016c..c0b73bc 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs | |||
@@ -178,7 +178,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
178 | // const d.ContactFlags comumContactFlags = d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM |d.ContactFlags.Approx1 | d.ContactFlags.Bounce; | 178 | // const d.ContactFlags comumContactFlags = d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM |d.ContactFlags.Approx1 | d.ContactFlags.Bounce; |
179 | 179 | ||
180 | const d.ContactFlags comumContactFlags = d.ContactFlags.Bounce | d.ContactFlags.Approx1 | d.ContactFlags.Slip1 | d.ContactFlags.Slip2; | 180 | const d.ContactFlags comumContactFlags = d.ContactFlags.Bounce | d.ContactFlags.Approx1 | d.ContactFlags.Slip1 | d.ContactFlags.Slip2; |
181 | const float comumContactERP = 0.7f; | 181 | const float comumContactERP = 0.75f; |
182 | const float comumContactCFM = 0.0001f; | 182 | const float comumContactCFM = 0.0001f; |
183 | const float comumContactSLIP = 0f; | 183 | const float comumContactSLIP = 0f; |
184 | 184 | ||
@@ -211,16 +211,13 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
211 | private float waterlevel = 0f; | 211 | private float waterlevel = 0f; |
212 | private int framecount = 0; | 212 | private int framecount = 0; |
213 | 213 | ||
214 | // private int m_meshExpireCntr; | ||
215 | |||
216 | private float avDensity = 80f; | 214 | private float avDensity = 80f; |
217 | private float avMovementDivisorWalk = 1.3f; | 215 | private float avMovementDivisorWalk = 1.3f; |
218 | private float avMovementDivisorRun = 0.8f; | 216 | private float avMovementDivisorRun = 0.8f; |
219 | private float minimumGroundFlightOffset = 3f; | 217 | private float minimumGroundFlightOffset = 3f; |
220 | public float maximumMassObject = 10000.01f; | 218 | public float maximumMassObject = 10000.01f; |
221 | 219 | ||
222 | 220 | public float geomDefaultDensity = 10.0f; | |
223 | public float geomDefaultDensity = 10.000006836f; | ||
224 | 221 | ||
225 | public float bodyPIDD = 35f; | 222 | public float bodyPIDD = 35f; |
226 | public float bodyPIDG = 25; | 223 | public float bodyPIDG = 25; |
@@ -243,17 +240,16 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
243 | private List<PhysicsActor> _collisionEventPrimRemove = new List<PhysicsActor>(); | 240 | private List<PhysicsActor> _collisionEventPrimRemove = new List<PhysicsActor>(); |
244 | 241 | ||
245 | private HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>(); | 242 | private HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>(); |
246 | // public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>(); | ||
247 | public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>(); | 243 | public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>(); |
248 | 244 | ||
249 | private float contactsurfacelayer = 0.001f; | 245 | private float contactsurfacelayer = 0.002f; |
250 | 246 | ||
251 | private int contactsPerCollision = 80; | 247 | private int contactsPerCollision = 80; |
252 | internal IntPtr ContactgeomsArray = IntPtr.Zero; | 248 | internal IntPtr ContactgeomsArray = IntPtr.Zero; |
253 | private IntPtr GlobalContactsArray = IntPtr.Zero; | 249 | private IntPtr GlobalContactsArray = IntPtr.Zero; |
254 | private d.Contact SharedTmpcontact = new d.Contact(); | 250 | private d.Contact SharedTmpcontact = new d.Contact(); |
255 | 251 | ||
256 | const int maxContactsbeforedeath = 4000; | 252 | const int maxContactsbeforedeath = 6000; |
257 | private volatile int m_global_contactcount = 0; | 253 | private volatile int m_global_contactcount = 0; |
258 | 254 | ||
259 | private IntPtr contactgroup; | 255 | private IntPtr contactgroup; |
@@ -271,7 +267,6 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
271 | 267 | ||
272 | public IntPtr world; | 268 | public IntPtr world; |
273 | 269 | ||
274 | |||
275 | // split the spaces acording to contents type | 270 | // split the spaces acording to contents type |
276 | // ActiveSpace contains characters and active prims | 271 | // ActiveSpace contains characters and active prims |
277 | // StaticSpace contains land and other that is mostly static in enviroment | 272 | // StaticSpace contains land and other that is mostly static in enviroment |
@@ -347,14 +342,12 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
347 | (float)m_frameWorkScene.RegionInfo.RegionSettings.WaterHeight); | 342 | (float)m_frameWorkScene.RegionInfo.RegionSettings.WaterHeight); |
348 | } | 343 | } |
349 | 344 | ||
350 | // core hack this just means all modules where loaded | ||
351 | // so now we can look for dependencies | ||
352 | public void RegionLoaded() | 345 | public void RegionLoaded() |
353 | { | 346 | { |
354 | mesher = m_frameWorkScene.RequestModuleInterface<IMesher>(); | 347 | mesher = m_frameWorkScene.RequestModuleInterface<IMesher>(); |
355 | if (mesher == null) | 348 | if (mesher == null) |
356 | { | 349 | { |
357 | m_log.WarnFormat("[ubOde] No mesher. module disabled"); | 350 | m_log.ErrorFormat("[ubOde] No mesher. module disabled"); |
358 | return; | 351 | return; |
359 | } | 352 | } |
360 | 353 | ||
@@ -453,7 +446,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
453 | } | 446 | } |
454 | 447 | ||
455 | 448 | ||
456 | // checkThread(); | 449 | // checkThread(); |
457 | 450 | ||
458 | 451 | ||
459 | // Defaults | 452 | // Defaults |
@@ -517,7 +510,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
517 | odetimestepMS = (int)(1000.0f * ODE_STEPSIZE + 0.5f); | 510 | odetimestepMS = (int)(1000.0f * ODE_STEPSIZE + 0.5f); |
518 | 511 | ||
519 | ContactgeomsArray = Marshal.AllocHGlobal(contactsPerCollision * d.ContactGeom.unmanagedSizeOf); | 512 | ContactgeomsArray = Marshal.AllocHGlobal(contactsPerCollision * d.ContactGeom.unmanagedSizeOf); |
520 | GlobalContactsArray = Marshal.AllocHGlobal(maxContactsbeforedeath * d.Contact.unmanagedSizeOf); | 513 | GlobalContactsArray = Marshal.AllocHGlobal((maxContactsbeforedeath + 100) * d.Contact.unmanagedSizeOf); |
521 | 514 | ||
522 | SharedTmpcontact.geom.g1 = IntPtr.Zero; | 515 | SharedTmpcontact.geom.g1 = IntPtr.Zero; |
523 | SharedTmpcontact.geom.g2 = IntPtr.Zero; | 516 | SharedTmpcontact.geom.g2 = IntPtr.Zero; |
@@ -1155,49 +1148,43 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
1155 | aprim.CollisionScore = 0; | 1148 | aprim.CollisionScore = 0; |
1156 | aprim.IsColliding = false; | 1149 | aprim.IsColliding = false; |
1157 | } | 1150 | } |
1158 | } | ||
1159 | 1151 | ||
1160 | // collide active prims with static enviroment | ||
1161 | lock (_activegroups) | ||
1162 | { | ||
1163 | try | 1152 | try |
1164 | { | 1153 | { |
1165 | foreach (OdePrim prm in _activegroups) | 1154 | foreach (OdePrim aprim in _activeprims) |
1166 | { | 1155 | { |
1167 | if (!prm.m_outbounds) | 1156 | if(d.BodyIsEnabled(aprim.Body)) |
1168 | { | 1157 | { |
1169 | if (d.BodyIsEnabled(prm.Body)) | 1158 | d.SpaceCollide2(StaticSpace, aprim.collide_geom, IntPtr.Zero, nearCallback); |
1170 | { | 1159 | d.SpaceCollide2(GroundSpace, aprim.collide_geom, IntPtr.Zero, nearCallback); |
1171 | d.SpaceCollide2(StaticSpace, prm.collide_geom, IntPtr.Zero, nearCallback); | ||
1172 | d.SpaceCollide2(GroundSpace, prm.collide_geom, IntPtr.Zero, nearCallback); | ||
1173 | } | ||
1174 | } | 1160 | } |
1175 | } | 1161 | } |
1176 | } | 1162 | } |
1177 | catch (AccessViolationException) | 1163 | catch (Exception e) |
1178 | { | 1164 | { |
1179 | m_log.Warn("[PHYSICS]: Unable to collide Active prim to static space"); | 1165 | m_log.Warn("[PHYSICS]: Unable to collide Active to Static: " + e.Message); |
1180 | } | 1166 | } |
1181 | } | 1167 | } |
1168 | |||
1182 | // colide active amoung them | 1169 | // colide active amoung them |
1183 | try | 1170 | try |
1184 | { | 1171 | { |
1185 | d.SpaceCollide(ActiveSpace, IntPtr.Zero, nearCallback); | 1172 | d.SpaceCollide(ActiveSpace, IntPtr.Zero, nearCallback); |
1186 | } | 1173 | } |
1187 | catch (AccessViolationException) | 1174 | catch (Exception e) |
1188 | { | 1175 | { |
1189 | m_log.Warn("[PHYSICS]: Unable to collide Active with Characters space"); | 1176 | m_log.Warn("[PHYSICS]: Unable to collide in Active: " + e.Message); |
1190 | } | 1177 | } |
1178 | |||
1191 | // and with chars | 1179 | // and with chars |
1192 | try | 1180 | try |
1193 | { | 1181 | { |
1194 | d.SpaceCollide2(CharsSpace,ActiveSpace, IntPtr.Zero, nearCallback); | 1182 | d.SpaceCollide2(CharsSpace,ActiveSpace, IntPtr.Zero, nearCallback); |
1195 | } | 1183 | } |
1196 | catch (AccessViolationException) | 1184 | catch (Exception e) |
1197 | { | 1185 | { |
1198 | m_log.Warn("[PHYSICS]: Unable to collide in Active space"); | 1186 | m_log.Warn("[PHYSICS]: Unable to collide Active to Character: " + e.Message); |
1199 | } | 1187 | } |
1200 | // _perloopContact.Clear(); | ||
1201 | } | 1188 | } |
1202 | 1189 | ||
1203 | #endregion | 1190 | #endregion |
@@ -1583,11 +1570,11 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
1583 | /// </summary> | 1570 | /// </summary> |
1584 | /// <param name="timeStep"></param> | 1571 | /// <param name="timeStep"></param> |
1585 | /// <returns></returns> | 1572 | /// <returns></returns> |
1586 | public override float Simulate(float timeStep) | 1573 | public override float Simulate(float reqTimeStep) |
1587 | { | 1574 | { |
1588 | DateTime now = DateTime.UtcNow; | 1575 | DateTime now = DateTime.UtcNow; |
1589 | TimeSpan timedif = now - m_lastframe; | 1576 | TimeSpan timedif = now - m_lastframe; |
1590 | timeStep = (float)timedif.TotalSeconds; | 1577 | float timeStep = (float)timedif.TotalSeconds; |
1591 | m_lastframe = now; | 1578 | m_lastframe = now; |
1592 | 1579 | ||
1593 | // acumulate time so we can reduce error | 1580 | // acumulate time so we can reduce error |
@@ -1601,16 +1588,9 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
1601 | 1588 | ||
1602 | framecount++; | 1589 | framecount++; |
1603 | 1590 | ||
1604 | // int curphysiteractions; | ||
1605 | |||
1606 | // if in trouble reduce step resolution | ||
1607 | // if (step_time >= m_SkipFramesAtms) | ||
1608 | // curphysiteractions = m_physicsiterations / 2; | ||
1609 | // else | ||
1610 | // curphysiteractions = m_physicsiterations; | ||
1611 | |||
1612 | // checkThread(); | 1591 | // checkThread(); |
1613 | int nodeframes = 0; | 1592 | int nodeframes = 0; |
1593 | float fps = 0; | ||
1614 | 1594 | ||
1615 | lock (SimulationLock) | 1595 | lock (SimulationLock) |
1616 | lock(OdeLock) | 1596 | lock(OdeLock) |
@@ -1627,8 +1607,36 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
1627 | 1607 | ||
1628 | int loopstartMS = Util.EnvironmentTickCount(); | 1608 | int loopstartMS = Util.EnvironmentTickCount(); |
1629 | int looptimeMS = 0; | 1609 | int looptimeMS = 0; |
1630 | 1610 | int changestimeMS = 0; | |
1611 | int maxChangestime = (int)(reqTimeStep * 500f); // half the time | ||
1612 | int maxLoopTime = (int)(reqTimeStep * 1200f); // 1.2 the time | ||
1613 | |||
1614 | if (ChangesQueue.Count > 0) | ||
1615 | { | ||
1616 | while (ChangesQueue.Dequeue(out item)) | ||
1617 | { | ||
1618 | if (item.actor != null) | ||
1619 | { | ||
1620 | try | ||
1621 | { | ||
1622 | if (item.actor is OdeCharacter) | ||
1623 | ((OdeCharacter)item.actor).DoAChange(item.what, item.arg); | ||
1624 | else if (((OdePrim)item.actor).DoAChange(item.what, item.arg)) | ||
1625 | RemovePrimThreadLocked((OdePrim)item.actor); | ||
1626 | } | ||
1627 | catch | ||
1628 | { | ||
1629 | m_log.WarnFormat("[PHYSICS]: doChange failed for a actor {0} {1}", | ||
1630 | item.actor.Name, item.what.ToString()); | ||
1631 | } | ||
1632 | } | ||
1633 | changestimeMS = Util.EnvironmentTickCountSubtract(loopstartMS); | ||
1634 | if (changestimeMS > maxChangestime) | ||
1635 | break; | ||
1636 | } | ||
1637 | } | ||
1631 | 1638 | ||
1639 | // do simulation taking at most 150ms total time including changes | ||
1632 | while (step_time > HalfOdeStep) | 1640 | while (step_time > HalfOdeStep) |
1633 | { | 1641 | { |
1634 | try | 1642 | try |
@@ -1636,32 +1644,6 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
1636 | // clear pointer/counter to contacts to pass into joints | 1644 | // clear pointer/counter to contacts to pass into joints |
1637 | m_global_contactcount = 0; | 1645 | m_global_contactcount = 0; |
1638 | 1646 | ||
1639 | if (ChangesQueue.Count > 0) | ||
1640 | { | ||
1641 | int changestartMS = Util.EnvironmentTickCount(); | ||
1642 | int ttmp; | ||
1643 | while (ChangesQueue.Dequeue(out item)) | ||
1644 | { | ||
1645 | if (item.actor != null) | ||
1646 | { | ||
1647 | try | ||
1648 | { | ||
1649 | if (item.actor is OdeCharacter) | ||
1650 | ((OdeCharacter)item.actor).DoAChange(item.what, item.arg); | ||
1651 | else if (((OdePrim)item.actor).DoAChange(item.what, item.arg)) | ||
1652 | RemovePrimThreadLocked((OdePrim)item.actor); | ||
1653 | } | ||
1654 | catch | ||
1655 | { | ||
1656 | m_log.WarnFormat("[PHYSICS]: doChange failed for a actor {0} {1}", | ||
1657 | item.actor.Name, item.what.ToString()); | ||
1658 | } | ||
1659 | } | ||
1660 | ttmp = Util.EnvironmentTickCountSubtract(changestartMS); | ||
1661 | if (ttmp > 20) | ||
1662 | break; | ||
1663 | } | ||
1664 | } | ||
1665 | 1647 | ||
1666 | // Move characters | 1648 | // Move characters |
1667 | lock (_characters) | 1649 | lock (_characters) |
@@ -1727,7 +1709,6 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
1727 | 1709 | ||
1728 | // do a ode simulation step | 1710 | // do a ode simulation step |
1729 | d.WorldQuickStep(world, ODE_STEPSIZE); | 1711 | d.WorldQuickStep(world, ODE_STEPSIZE); |
1730 | // d.WorldStep(world, ODE_STEPSIZE); | ||
1731 | d.JointGroupEmpty(contactgroup); | 1712 | d.JointGroupEmpty(contactgroup); |
1732 | 1713 | ||
1733 | // update managed ideia of physical data and do updates to core | 1714 | // update managed ideia of physical data and do updates to core |
@@ -1770,7 +1751,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
1770 | nodeframes++; | 1751 | nodeframes++; |
1771 | 1752 | ||
1772 | looptimeMS = Util.EnvironmentTickCountSubtract(loopstartMS); | 1753 | looptimeMS = Util.EnvironmentTickCountSubtract(loopstartMS); |
1773 | if (looptimeMS > 100) | 1754 | if (looptimeMS > maxLoopTime) |
1774 | break; | 1755 | break; |
1775 | } | 1756 | } |
1776 | 1757 | ||
@@ -1795,7 +1776,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
1795 | m_lastMeshExpire = now; | 1776 | m_lastMeshExpire = now; |
1796 | } | 1777 | } |
1797 | 1778 | ||
1798 | // information block running in debug only | 1779 | // information block for in debug breakpoint only |
1799 | /* | 1780 | /* |
1800 | int ntopactivegeoms = d.SpaceGetNumGeoms(ActiveSpace); | 1781 | int ntopactivegeoms = d.SpaceGetNumGeoms(ActiveSpace); |
1801 | int ntopstaticgeoms = d.SpaceGetNumGeoms(StaticSpace); | 1782 | int ntopstaticgeoms = d.SpaceGetNumGeoms(StaticSpace); |
@@ -1857,21 +1838,26 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
1857 | d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); | 1838 | d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); |
1858 | } | 1839 | } |
1859 | 1840 | ||
1860 | // think time dilation as to do with dinamic step size that we dont' have | 1841 | fps = (float)nodeframes * ODE_STEPSIZE / reqTimeStep; |
1861 | // even so tell something to world | 1842 | |
1862 | if (looptimeMS < 100) // we did the requested loops | 1843 | if(step_time < HalfOdeStep) |
1863 | m_timeDilation = 1.0f; | 1844 | m_timeDilation = 1.0f; |
1864 | else if (step_time > 0) | 1845 | else if (step_time > m_SkipFramesAtms) |
1865 | { | 1846 | { |
1866 | m_timeDilation = timeStep / step_time; | 1847 | // if we lag too much skip frames |
1848 | m_timeDilation = 0.0f; | ||
1849 | step_time = 0; | ||
1850 | m_lastframe = DateTime.UtcNow; // skip also the time lost | ||
1851 | } | ||
1852 | else | ||
1853 | { | ||
1854 | m_timeDilation = ODE_STEPSIZE / step_time; | ||
1867 | if (m_timeDilation > 1) | 1855 | if (m_timeDilation > 1) |
1868 | m_timeDilation = 1; | 1856 | m_timeDilation = 1; |
1869 | if (step_time > m_SkipFramesAtms) | ||
1870 | step_time = 0; | ||
1871 | m_lastframe = DateTime.UtcNow; // skip also the time lost | ||
1872 | } | 1857 | } |
1873 | } | 1858 | } |
1874 | return (float)nodeframes * ODE_STEPSIZE / timeStep; | 1859 | |
1860 | return fps; | ||
1875 | } | 1861 | } |
1876 | 1862 | ||
1877 | /// <summary> | 1863 | /// <summary> |
@@ -2442,12 +2428,13 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
2442 | 2428 | ||
2443 | public override void Dispose() | 2429 | public override void Dispose() |
2444 | { | 2430 | { |
2445 | if (m_rayCastManager == null) // if this is null we already did dispose | ||
2446 | return; | ||
2447 | lock (OdeLock) | 2431 | lock (OdeLock) |
2448 | { | 2432 | { |
2433 | if (world == IntPtr.Zero) | ||
2434 | return; | ||
2435 | |||
2449 | if (m_meshWorker != null) | 2436 | if (m_meshWorker != null) |
2450 | m_meshWorker.Stop(); | 2437 | m_meshWorker.Stop(); |
2451 | 2438 | ||
2452 | if (m_rayCastManager != null) | 2439 | if (m_rayCastManager != null) |
2453 | { | 2440 | { |
@@ -2484,7 +2471,6 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
2484 | d.GeomDestroy(GroundGeom); | 2471 | d.GeomDestroy(GroundGeom); |
2485 | } | 2472 | } |
2486 | 2473 | ||
2487 | |||
2488 | RegionTerrain.Clear(); | 2474 | RegionTerrain.Clear(); |
2489 | 2475 | ||
2490 | if (TerrainHeightFieldHeightsHandlers.Count > 0) | 2476 | if (TerrainHeightFieldHeightsHandlers.Count > 0) |
@@ -2500,10 +2486,15 @@ namespace OpenSim.Region.PhysicsModule.ubOde | |||
2500 | TerrainHeightFieldHeights.Clear(); | 2486 | TerrainHeightFieldHeights.Clear(); |
2501 | 2487 | ||
2502 | if (ContactgeomsArray != IntPtr.Zero) | 2488 | if (ContactgeomsArray != IntPtr.Zero) |
2489 | { | ||
2503 | Marshal.FreeHGlobal(ContactgeomsArray); | 2490 | Marshal.FreeHGlobal(ContactgeomsArray); |
2491 | ContactgeomsArray = IntPtr.Zero; | ||
2492 | } | ||
2504 | if (GlobalContactsArray != IntPtr.Zero) | 2493 | if (GlobalContactsArray != IntPtr.Zero) |
2494 | { | ||
2505 | Marshal.FreeHGlobal(GlobalContactsArray); | 2495 | Marshal.FreeHGlobal(GlobalContactsArray); |
2506 | 2496 | GlobalContactsArray = IntPtr.Zero; | |
2497 | } | ||
2507 | 2498 | ||
2508 | d.WorldDestroy(world); | 2499 | d.WorldDestroy(world); |
2509 | world = IntPtr.Zero; | 2500 | world = IntPtr.Zero; |