PageRenderTime 65ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs

https://gitlab.com/N3X15/VoxelSim
C# | 3758 lines | 2460 code | 479 blank | 819 comment | 478 complexity | 171260a727b01f2dffc7410dfb31181e MD5 | raw file
Possible License(s): BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  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 copyright
  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. */
  27. //#define USE_DRAWSTUFF
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Reflection;
  31. using System.Runtime.InteropServices;
  32. using System.Threading;
  33. using System.IO;
  34. using System.Diagnostics;
  35. using log4net;
  36. using Nini.Config;
  37. using Ode.NET;
  38. #if USE_DRAWSTUFF
  39. using Drawstuff.NET;
  40. #endif
  41. using OpenSim.Framework;
  42. using OpenSim.Region.Physics.Manager;
  43. using OpenMetaverse;
  44. //using OpenSim.Region.Physics.OdePlugin.Meshing;
  45. namespace OpenSim.Region.Physics.OdePlugin
  46. {
  47. /// <summary>
  48. /// ODE plugin
  49. /// </summary>
  50. public class OdePlugin : IPhysicsPlugin
  51. {
  52. //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  53. private CollisionLocker ode;
  54. private OdeScene _mScene;
  55. public OdePlugin()
  56. {
  57. ode = new CollisionLocker();
  58. }
  59. public bool Init()
  60. {
  61. return true;
  62. }
  63. public PhysicsScene GetScene(String sceneIdentifier)
  64. {
  65. if (_mScene == null)
  66. {
  67. // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to
  68. // http://opensimulator.org/mantis/view.php?id=2750).
  69. d.InitODE();
  70. _mScene = new OdeScene(ode, sceneIdentifier);
  71. }
  72. return (_mScene);
  73. }
  74. public string GetName()
  75. {
  76. return ("OpenDynamicsEngine");
  77. }
  78. public void Dispose()
  79. {
  80. }
  81. }
  82. public enum StatusIndicators : int
  83. {
  84. Generic = 0,
  85. Start = 1,
  86. End = 2
  87. }
  88. public struct sCollisionData
  89. {
  90. public uint ColliderLocalId;
  91. public uint CollidedWithLocalId;
  92. public int NumberOfCollisions;
  93. public int CollisionType;
  94. public int StatusIndicator;
  95. public int lastframe;
  96. }
  97. [Flags]
  98. public enum CollisionCategories : int
  99. {
  100. Disabled = 0,
  101. Geom = 0x00000001,
  102. Body = 0x00000002,
  103. Space = 0x00000004,
  104. Character = 0x00000008,
  105. Land = 0x00000010,
  106. Water = 0x00000020,
  107. Wind = 0x00000040,
  108. Sensor = 0x00000080,
  109. Selected = 0x00000100
  110. }
  111. /// <summary>
  112. /// Material type for a primitive
  113. /// </summary>
  114. public enum Material : int
  115. {
  116. /// <summary></summary>
  117. Stone = 0,
  118. /// <summary></summary>
  119. Metal = 1,
  120. /// <summary></summary>
  121. Glass = 2,
  122. /// <summary></summary>
  123. Wood = 3,
  124. /// <summary></summary>
  125. Flesh = 4,
  126. /// <summary></summary>
  127. Plastic = 5,
  128. /// <summary></summary>
  129. Rubber = 6
  130. }
  131. public sealed class OdeScene : PhysicsScene
  132. {
  133. private readonly ILog m_log;
  134. // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
  135. CollisionLocker ode;
  136. private Random fluidRandomizer = new Random(Environment.TickCount);
  137. private const uint m_regionWidth = Constants.RegionSize;
  138. private const uint m_regionHeight = Constants.RegionSize;
  139. private float ODE_STEPSIZE = 0.020f;
  140. private float metersInSpace = 29.9f;
  141. private float m_timeDilation = 1.0f;
  142. public float gravityx = 0f;
  143. public float gravityy = 0f;
  144. public float gravityz = -9.8f;
  145. private float contactsurfacelayer = 0.001f;
  146. private int worldHashspaceLow = -4;
  147. private int worldHashspaceHigh = 128;
  148. private int smallHashspaceLow = -4;
  149. private int smallHashspaceHigh = 66;
  150. private float waterlevel = 0f;
  151. private int framecount = 0;
  152. //private int m_returncollisions = 10;
  153. private readonly IntPtr contactgroup;
  154. internal IntPtr LandGeom;
  155. internal IntPtr WaterGeom;
  156. private float nmTerrainContactFriction = 255.0f;
  157. private float nmTerrainContactBounce = 0.1f;
  158. private float nmTerrainContactERP = 0.1025f;
  159. private float mTerrainContactFriction = 75f;
  160. private float mTerrainContactBounce = 0.1f;
  161. private float mTerrainContactERP = 0.05025f;
  162. private float nmAvatarObjectContactFriction = 250f;
  163. private float nmAvatarObjectContactBounce = 0.1f;
  164. private float mAvatarObjectContactFriction = 75f;
  165. private float mAvatarObjectContactBounce = 0.1f;
  166. private float avPIDD = 3200f;
  167. private float avPIDP = 1400f;
  168. private float avCapRadius = 0.37f;
  169. private float avStandupTensor = 2000000f;
  170. private bool avCapsuleTilted = true; // true = old compatibility mode with leaning capsule; false = new corrected mode
  171. public bool IsAvCapsuleTilted { get { return avCapsuleTilted; } set { avCapsuleTilted = value; } }
  172. private float avDensity = 80f;
  173. private float avHeightFudgeFactor = 0.52f;
  174. private float avMovementDivisorWalk = 1.3f;
  175. private float avMovementDivisorRun = 0.8f;
  176. private float minimumGroundFlightOffset = 3f;
  177. public float maximumMassObject = 10000.01f;
  178. public bool meshSculptedPrim = true;
  179. public bool forceSimplePrimMeshing = false;
  180. public float meshSculptLOD = 32;
  181. public float MeshSculptphysicalLOD = 16;
  182. public float geomDefaultDensity = 10.000006836f;
  183. public int geomContactPointsStartthrottle = 3;
  184. public int geomUpdatesPerThrottledUpdate = 15;
  185. public float bodyPIDD = 35f;
  186. public float bodyPIDG = 25;
  187. public int geomCrossingFailuresBeforeOutofbounds = 5;
  188. public float bodyMotorJointMaxforceTensor = 2;
  189. public int bodyFramesAutoDisable = 20;
  190. private float[] _watermap;
  191. private bool m_filterCollisions = true;
  192. private d.NearCallback nearCallback;
  193. public d.TriCallback triCallback;
  194. public d.TriArrayCallback triArrayCallback;
  195. private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
  196. private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
  197. private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
  198. private readonly HashSet<OdePrim> _taintedPrimH = new HashSet<OdePrim>();
  199. private readonly Object _taintedPrimLock = new Object();
  200. private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>();
  201. private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
  202. private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
  203. private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
  204. private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
  205. public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
  206. public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
  207. private bool m_NINJA_physics_joints_enabled = false;
  208. //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
  209. private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
  210. private d.ContactGeom[] contacts;
  211. private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
  212. private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
  213. private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
  214. private readonly List<string> requestedJointsToBeDeleted = new List<string>(); // lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active
  215. private Object externalJointRequestsLock = new Object();
  216. private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
  217. private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
  218. private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
  219. private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
  220. private d.Contact contact;
  221. private d.Contact TerrainContact;
  222. private d.Contact AvatarMovementprimContact;
  223. private d.Contact AvatarMovementTerrainContact;
  224. private d.Contact WaterContact;
  225. private d.Contact[,] m_materialContacts;
  226. //Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
  227. //Ckrinke private int m_randomizeWater = 200;
  228. private int m_physicsiterations = 10;
  229. private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
  230. private readonly PhysicsActor PANull = new NullPhysicsActor();
  231. private float step_time = 0.0f;
  232. //Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
  233. //Ckrinke private int ms = 0;
  234. public IntPtr world;
  235. //private bool returncollisions = false;
  236. // private uint obj1LocalID = 0;
  237. private uint obj2LocalID = 0;
  238. //private int ctype = 0;
  239. private OdeCharacter cc1;
  240. private OdePrim cp1;
  241. private OdeCharacter cc2;
  242. private OdePrim cp2;
  243. //private int cStartStop = 0;
  244. //private string cDictKey = "";
  245. public IntPtr space;
  246. //private IntPtr tmpSpace;
  247. // split static geometry collision handling into spaces of 30 meters
  248. public IntPtr[,] staticPrimspace;
  249. public Object OdeLock;
  250. public IMesher mesher;
  251. public IVoxelMesher voxmesher;
  252. private IConfigSource m_config;
  253. public bool physics_logging = false;
  254. public int physics_logging_interval = 0;
  255. public bool physics_logging_append_existing_logfile = false;
  256. public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
  257. public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
  258. // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
  259. // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
  260. // TODO: unused: private uint mapWidthSamples;
  261. // TODO: unused: private uint heightmapHeightSamples;
  262. private volatile int m_global_contactcount = 0;
  263. private Vector3 m_worldOffset = Vector3.Zero;
  264. public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
  265. private PhysicsScene m_parentScene = null;
  266. private ODERayCastRequestManager m_rayCastManager;
  267. /// <summary>
  268. /// Initiailizes the scene
  269. /// Sets many properties that ODE requires to be stable
  270. /// These settings need to be tweaked 'exactly' right or weird stuff happens.
  271. /// </summary>
  272. public OdeScene(CollisionLocker dode, string sceneIdentifier)
  273. {
  274. m_log
  275. = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier);
  276. OdeLock = new Object();
  277. ode = dode;
  278. nearCallback = near;
  279. triCallback = TriCallback;
  280. triArrayCallback = TriArrayCallback;
  281. m_rayCastManager = new ODERayCastRequestManager(this);
  282. lock (OdeLock)
  283. {
  284. // Create the world and the first space
  285. world = d.WorldCreate();
  286. space = d.HashSpaceCreate(IntPtr.Zero);
  287. contactgroup = d.JointGroupCreate(0);
  288. //contactgroup
  289. d.WorldSetAutoDisableFlag(world, false);
  290. #if USE_DRAWSTUFF
  291. Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
  292. viewthread.Start();
  293. #endif
  294. }
  295. _watermap = new float[258 * 258];
  296. // Zero out the prim spaces array (we split our space into smaller spaces so
  297. // we can hit test less.
  298. }
  299. #if USE_DRAWSTUFF
  300. public void startvisualization(object o)
  301. {
  302. ds.Functions fn;
  303. fn.version = ds.VERSION;
  304. fn.start = new ds.CallbackFunction(start);
  305. fn.step = new ds.CallbackFunction(step);
  306. fn.command = new ds.CallbackFunction(command);
  307. fn.stop = null;
  308. fn.path_to_textures = "./textures";
  309. string[] args = new string[0];
  310. ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
  311. }
  312. #endif
  313. // Initialize the mesh plugin
  314. public override void Initialise(IMesher meshmerizer, IVoxelMesher voxmesh, IConfigSource config)
  315. {
  316. mesher = meshmerizer;
  317. voxmesher = voxmesh;
  318. m_config = config;
  319. // Defaults
  320. if (Environment.OSVersion.Platform == PlatformID.Unix)
  321. {
  322. avPIDD = 3200.0f;
  323. avPIDP = 1400.0f;
  324. avStandupTensor = 2000000f;
  325. }
  326. else
  327. {
  328. avPIDD = 2200.0f;
  329. avPIDP = 900.0f;
  330. avStandupTensor = 550000f;
  331. }
  332. int contactsPerCollision = 80;
  333. if (m_config != null)
  334. {
  335. IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
  336. if (physicsconfig != null)
  337. {
  338. gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
  339. gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
  340. gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
  341. worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
  342. worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
  343. metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
  344. smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
  345. smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
  346. contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
  347. nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
  348. nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
  349. nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
  350. mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
  351. mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
  352. mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
  353. nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
  354. nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
  355. mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
  356. mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
  357. ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", 0.020f);
  358. m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
  359. avDensity = physicsconfig.GetFloat("av_density", 80f);
  360. avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
  361. avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
  362. avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
  363. avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
  364. avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
  365. contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
  366. geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3);
  367. geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
  368. geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
  369. geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
  370. bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
  371. bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
  372. bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
  373. forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
  374. meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
  375. meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
  376. MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
  377. m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
  378. if (Environment.OSVersion.Platform == PlatformID.Unix)
  379. {
  380. avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
  381. avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
  382. avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
  383. bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
  384. }
  385. else
  386. {
  387. avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
  388. avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
  389. avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
  390. bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
  391. }
  392. physics_logging = physicsconfig.GetBoolean("physics_logging", false);
  393. physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
  394. physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
  395. m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
  396. minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
  397. maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
  398. }
  399. }
  400. contacts = new d.ContactGeom[contactsPerCollision];
  401. staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
  402. // Centeral contact friction and bounce
  403. // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
  404. // an avatar falls through in Z but not in X or Y when walking on a prim.
  405. contact.surface.mode |= d.ContactFlags.SoftERP;
  406. contact.surface.mu = nmAvatarObjectContactFriction;
  407. contact.surface.bounce = nmAvatarObjectContactBounce;
  408. contact.surface.soft_cfm = 0.010f;
  409. contact.surface.soft_erp = 0.010f;
  410. // Terrain contact friction and Bounce
  411. // This is the *non* moving version. Use this when an avatar
  412. // isn't moving to keep it in place better
  413. TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
  414. TerrainContact.surface.mu = nmTerrainContactFriction;
  415. TerrainContact.surface.bounce = nmTerrainContactBounce;
  416. TerrainContact.surface.soft_erp = nmTerrainContactERP;
  417. WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
  418. WaterContact.surface.mu = 0f; // No friction
  419. WaterContact.surface.bounce = 0.0f; // No bounce
  420. WaterContact.surface.soft_cfm = 0.010f;
  421. WaterContact.surface.soft_erp = 0.010f;
  422. // Prim contact friction and bounce
  423. // THis is the *non* moving version of friction and bounce
  424. // Use this when an avatar comes in contact with a prim
  425. // and is moving
  426. AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
  427. AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
  428. // Terrain contact friction bounce and various error correcting calculations
  429. // Use this when an avatar is in contact with the terrain and moving.
  430. AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
  431. AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
  432. AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
  433. AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
  434. /*
  435. <summary></summary>
  436. Stone = 0,
  437. /// <summary></summary>
  438. Metal = 1,
  439. /// <summary></summary>
  440. Glass = 2,
  441. /// <summary></summary>
  442. Wood = 3,
  443. /// <summary></summary>
  444. Flesh = 4,
  445. /// <summary></summary>
  446. Plastic = 5,
  447. /// <summary></summary>
  448. Rubber = 6
  449. */
  450. m_materialContacts = new d.Contact[7,2];
  451. m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
  452. m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
  453. m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
  454. m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
  455. m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
  456. m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
  457. m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
  458. m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
  459. m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
  460. m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
  461. m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
  462. m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
  463. m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
  464. m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
  465. m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
  466. m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
  467. m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
  468. m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
  469. m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
  470. m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
  471. m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
  472. m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
  473. m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
  474. m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
  475. m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
  476. m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
  477. m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
  478. m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
  479. m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
  480. m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
  481. /*
  482. private float nmAvatarObjectContactFriction = 250f;
  483. private float nmAvatarObjectContactBounce = 0.1f;
  484. private float mAvatarObjectContactFriction = 75f;
  485. private float mAvatarObjectContactBounce = 0.1f;
  486. */
  487. m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
  488. m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
  489. m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
  490. m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
  491. m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
  492. m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
  493. m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
  494. m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
  495. m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
  496. m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
  497. m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
  498. m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
  499. m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
  500. m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
  501. m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
  502. m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
  503. m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
  504. m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
  505. m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
  506. m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
  507. m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
  508. m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
  509. m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
  510. m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
  511. m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
  512. m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
  513. m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
  514. m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
  515. m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
  516. m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
  517. m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
  518. m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
  519. m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
  520. m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
  521. m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
  522. m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
  523. m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
  524. m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
  525. m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
  526. m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
  527. m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
  528. m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
  529. m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
  530. m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
  531. m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
  532. m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
  533. m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
  534. m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
  535. m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
  536. m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
  537. m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
  538. m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
  539. m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
  540. m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
  541. d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
  542. // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
  543. d.WorldSetGravity(world, gravityx, gravityy, gravityz);
  544. d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
  545. d.WorldSetLinearDamping(world, 256f);
  546. d.WorldSetAngularDamping(world, 256f);
  547. d.WorldSetAngularDampingThreshold(world, 256f);
  548. d.WorldSetLinearDampingThreshold(world, 256f);
  549. d.WorldSetMaxAngularSpeed(world, 256f);
  550. // Set how many steps we go without running collision testing
  551. // This is in addition to the step size.
  552. // Essentially Steps * m_physicsiterations
  553. d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
  554. //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
  555. for (int i = 0; i < staticPrimspace.GetLength(0); i++)
  556. {
  557. for (int j = 0; j < staticPrimspace.GetLength(1); j++)
  558. {
  559. staticPrimspace[i, j] = IntPtr.Zero;
  560. }
  561. }
  562. }
  563. internal void waitForSpaceUnlock(IntPtr space)
  564. {
  565. //if (space != IntPtr.Zero)
  566. //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
  567. }
  568. /// <summary>
  569. /// Debug space message for printing the space that a prim/avatar is in.
  570. /// </summary>
  571. /// <param name="pos"></param>
  572. /// <returns>Returns which split up space the given position is in.</returns>
  573. public string whichspaceamIin(Vector3 pos)
  574. {
  575. return calculateSpaceForGeom(pos).ToString();
  576. }
  577. #region Collision Detection
  578. /// <summary>
  579. /// This is our near callback. A geometry is near a body
  580. /// </summary>
  581. /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
  582. /// <param name="g1">a geometry or space</param>
  583. /// <param name="g2">another geometry or space</param>
  584. private void near(IntPtr space, IntPtr g1, IntPtr g2)
  585. {
  586. // no lock here! It's invoked from within Simulate(), which is thread-locked
  587. // Test if we're colliding a geom with a space.
  588. // If so we have to drill down into the space recursively
  589. if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
  590. {
  591. if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
  592. return;
  593. // Separating static prim geometry spaces.
  594. // We'll be calling near recursivly if one
  595. // of them is a space to find all of the
  596. // contact points in the space
  597. try
  598. {
  599. d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
  600. }
  601. catch (AccessViolationException)
  602. {
  603. m_log.Warn("[PHYSICS]: Unable to collide test a space");
  604. return;
  605. }
  606. //Colliding a space or a geom with a space or a geom. so drill down
  607. //Collide all geoms in each space..
  608. //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
  609. //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
  610. return;
  611. }
  612. if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
  613. return;
  614. IntPtr b1 = d.GeomGetBody(g1);
  615. IntPtr b2 = d.GeomGetBody(g2);
  616. // d.GeomClassID id = d.GeomGetClass(g1);
  617. String name1 = null;
  618. String name2 = null;
  619. if (!geom_name_map.TryGetValue(g1, out name1))
  620. {
  621. name1 = "null";
  622. }
  623. if (!geom_name_map.TryGetValue(g2, out name2))
  624. {
  625. name2 = "null";
  626. }
  627. //if (id == d.GeomClassId.TriMeshClass)
  628. //{
  629. // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
  630. //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
  631. //}
  632. // Figure out how many contact points we have
  633. int count = 0;
  634. try
  635. {
  636. // Colliding Geom To Geom
  637. // This portion of the function 'was' blatantly ripped off from BoxStack.cs
  638. if (g1 == g2)
  639. return; // Can't collide with yourself
  640. if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
  641. return;
  642. lock (contacts)
  643. {
  644. count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
  645. if (count > contacts.Length)
  646. m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
  647. }
  648. }
  649. catch (SEHException)
  650. {
  651. m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
  652. ode.drelease(world);
  653. base.TriggerPhysicsBasedRestart();
  654. }
  655. catch (Exception e)
  656. {
  657. m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
  658. return;
  659. }
  660. PhysicsActor p1;
  661. PhysicsActor p2;
  662. if (!actor_name_map.TryGetValue(g1, out p1))
  663. {
  664. p1 = PANull;
  665. }
  666. if (!actor_name_map.TryGetValue(g2, out p2))
  667. {
  668. p2 = PANull;
  669. }
  670. ContactPoint maxDepthContact = new ContactPoint();
  671. if (p1.CollisionScore + count >= float.MaxValue)
  672. p1.CollisionScore = 0;
  673. p1.CollisionScore += count;
  674. if (p2.CollisionScore + count >= float.MaxValue)
  675. p2.CollisionScore = 0;
  676. p2.CollisionScore += count;
  677. for (int i = 0; i < count; i++)
  678. {
  679. d.ContactGeom curContact = contacts[i];
  680. if (curContact.depth > maxDepthContact.PenetrationDepth)
  681. {
  682. maxDepthContact = new ContactPoint(
  683. new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
  684. new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
  685. curContact.depth
  686. );
  687. }
  688. //m_log.Warn("[CCOUNT]: " + count);
  689. IntPtr joint;
  690. // If we're colliding with terrain, use 'TerrainContact' instead of contact.
  691. // allows us to have different settings
  692. // We only need to test p2 for 'jump crouch purposes'
  693. if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
  694. {
  695. // Testing if the collision is at the feet of the avatar
  696. //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f));
  697. if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
  698. p2.IsColliding = true;
  699. }
  700. else
  701. {
  702. p2.IsColliding = true;
  703. }
  704. //if ((framecount % m_returncollisions) == 0)
  705. switch (p1.PhysicsActorType)
  706. {
  707. case (int)ActorTypes.Agent:
  708. p2.CollidingObj = true;
  709. break;
  710. case (int)ActorTypes.Prim:
  711. if (p2.Velocity.LengthSquared() > 0.0f)
  712. p2.CollidingObj = true;
  713. break;
  714. case (int)ActorTypes.Unknown:
  715. p2.CollidingGround = true;
  716. break;
  717. default:
  718. p2.CollidingGround = true;
  719. break;
  720. }
  721. // we don't want prim or avatar to explode
  722. #region InterPenetration Handling - Unintended physics explosions
  723. # region disabled code1
  724. if (curContact.depth >= 0.08f)
  725. {
  726. //This is disabled at the moment only because it needs more tweaking
  727. //It will eventually be uncommented
  728. /*
  729. if (contact.depth >= 1.00f)
  730. {
  731. //m_log.Debug("[PHYSICS]: " + contact.depth.ToString());
  732. }
  733. //If you interpenetrate a prim with an agent
  734. if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
  735. p1.PhysicsActorType == (int) ActorTypes.Prim) ||
  736. (p1.PhysicsActorType == (int) ActorTypes.Agent &&
  737. p2.PhysicsActorType == (int) ActorTypes.Prim))
  738. {
  739. //contact.depth = contact.depth * 4.15f;
  740. /*
  741. if (p2.PhysicsActorType == (int) ActorTypes.Agent)
  742. {
  743. p2.CollidingObj = true;
  744. contact.depth = 0.003f;
  745. p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
  746. OdeCharacter character = (OdeCharacter) p2;
  747. character.SetPidStatus(true);
  748. contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2));
  749. }
  750. else
  751. {
  752. //contact.depth = 0.0000000f;
  753. }
  754. if (p1.PhysicsActorType == (int) ActorTypes.Agent)
  755. {
  756. p1.CollidingObj = true;
  757. contact.depth = 0.003f;
  758. p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
  759. contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2));
  760. OdeCharacter character = (OdeCharacter)p1;
  761. character.SetPidStatus(true);
  762. }
  763. else
  764. {
  765. //contact.depth = 0.0000000f;
  766. }
  767. }
  768. */
  769. // If you interpenetrate a prim with another prim
  770. /*
  771. if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
  772. {
  773. #region disabledcode2
  774. //OdePrim op1 = (OdePrim)p1;
  775. //OdePrim op2 = (OdePrim)p2;
  776. //op1.m_collisionscore++;
  777. //op2.m_collisionscore++;
  778. //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
  779. //{
  780. //op1.m_taintdisable = true;
  781. //AddPhysicsActorTaint(p1);
  782. //op2.m_taintdisable = true;
  783. //AddPhysicsActorTaint(p2);
  784. //}
  785. //if (contact.depth >= 0.25f)
  786. //{
  787. // Don't collide, one or both prim will expld.
  788. //op1.m_interpenetrationcount++;
  789. //op2.m_interpenetrationcount++;
  790. //interpenetrations_before_disable = 200;
  791. //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
  792. //{
  793. //op1.m_taintdisable = true;
  794. //AddPhysicsActorTaint(p1);
  795. //}
  796. //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
  797. //{
  798. // op2.m_taintdisable = true;
  799. //AddPhysicsActorTaint(p2);
  800. //}
  801. //contact.depth = contact.depth / 8f;
  802. //contact.normal = new d.Vector3(0, 0, 1);
  803. //}
  804. //if (op1.m_disabled || op2.m_disabled)
  805. //{
  806. //Manually disabled objects stay disabled
  807. //contact.depth = 0f;
  808. //}
  809. #endregion
  810. }
  811. */
  812. #endregion
  813. if (curContact.depth >= 1.00f)
  814. {
  815. //m_log.Info("[P]: " + contact.depth.ToString());
  816. if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
  817. p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
  818. (p1.PhysicsActorType == (int) ActorTypes.Agent &&
  819. p2.PhysicsActorType == (int) ActorTypes.Unknown))
  820. {
  821. if (p2.PhysicsActorType == (int) ActorTypes.Agent)
  822. {
  823. if (p2 is OdeCharacter)
  824. {
  825. OdeCharacter character = (OdeCharacter) p2;
  826. //p2.CollidingObj = true;
  827. curContact.depth = 0.00000003f;
  828. p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
  829. curContact.pos =
  830. new d.Vector3(curContact.pos.X + (p1.Size.X/2),
  831. curContact.pos.Y + (p1.Size.Y/2),
  832. curContact.pos.Z + (p1.Size.Z/2));
  833. character.SetPidStatus(true);
  834. }
  835. }
  836. if (p1.PhysicsActorType == (int) ActorTypes.Agent)
  837. {
  838. if (p1 is OdeCharacter)
  839. {
  840. OdeCharacter character = (OdeCharacter) p1;
  841. //p2.CollidingObj = true;
  842. curContact.depth = 0.00000003f;
  843. p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
  844. curContact.pos =
  845. new d.Vector3(curContact.pos.X + (p1.Size.X/2),
  846. curContact.pos.Y + (p1.Size.Y/2),
  847. curContact.pos.Z + (p1.Size.Z/2));
  848. character.SetPidStatus(true);
  849. }
  850. }
  851. }
  852. }
  853. }
  854. #endregion
  855. // Logic for collision handling
  856. // Note, that if *all* contacts are skipped (VolumeDetect)
  857. // The prim still detects (and forwards) collision events but
  858. // appears to be phantom for the world
  859. Boolean skipThisContact = false;
  860. if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
  861. skipThisContact = true; // No collision on volume detect prims
  862. if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
  863. skipThisContact = true; // No collision on volume detect prims
  864. if (!skipThisContact && curContact.depth < 0f)
  865. skipThisContact = true;
  866. if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
  867. skipThisContact = true;
  868. const int maxContactsbeforedeath = 4000;
  869. joint = IntPtr.Zero;
  870. if (!skipThisContact)
  871. {
  872. // If we're colliding against terrain
  873. if (name1 == "Terrain" || name2 == "Terrain")
  874. {
  875. // If we're moving
  876. if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
  877. (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
  878. {
  879. // Use the movement terrain contact
  880. AvatarMovementTerrainContact.geom = curContact;
  881. _perloopContact.Add(curContact);
  882. if (m_global_contactcount < maxContactsbeforedeath)
  883. {
  884. joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
  885. m_global_contactcount++;
  886. }
  887. }
  888. else
  889. {
  890. if (p2.PhysicsActorType == (int)ActorTypes.Agent)
  891. {

Large files files are truncated, but you can click here to view the full file