From a94ce3f1dfcc6334538e28e51dcf2e5eb8858193 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 15:30:00 +0000 Subject: [PATCH 01/38] Move DeleteScriptsOnStartup switch from [Startup] to [XEngine] in OpenSim.ini.example. If anybody was changing this and wondering why there was no effect, this is why. --- bin/OpenSim.ini.example | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index e31d0f4244..d4e61a559b 100755 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -231,13 +231,6 @@ ;; server to send mail through. ; emailmodule = DefaultEmailModule - ;# {DeleteScriptsOnStartup} {} {Delete previously compiled script DLLs on startup?} (true false) true - ;; Controls whether previously compiled scripts DLLs are deleted on sim restart. If you set this to false - ;; then startup will be considerably faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the - ;; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used - ;; by scripts have changed. - ; DeleteScriptsOnStartup = true - [SMTP] ;; The SMTP server enabled the email module to send email to external ;; destinations. @@ -571,6 +564,13 @@ ;; Stack size per thread created ; ThreadStackSize = 262144 + ;# {DeleteScriptsOnStartup} {} {Delete previously compiled script DLLs on startup?} (true false) true + ;; Controls whether previously compiled scripts DLLs are deleted on sim restart. If you set this to false + ;; then startup will be considerably faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the + ;; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used + ;; by scripts have changed. + ; DeleteScriptsOnStartup = true + ;; Set this to true (the default) to load each script into a separate ;; AppDomain. Setting this to false will load all script assemblies into the ;; current AppDomain, which will reduce the per-script overhead at the From 4485007fce3578079d200d15e5988355772fa592 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 17:04:54 +0000 Subject: [PATCH 02/38] Instead of generating a new list for bad characters on every physics pass, keep reusing the same list. --- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 43d852b05e..fe2b2b2e5a 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -188,10 +188,19 @@ namespace OpenSim.Region.Physics.OdePlugin private d.NearCallback nearCallback; public d.TriCallback triCallback; public d.TriArrayCallback triArrayCallback; + private readonly HashSet _characters = new HashSet(); private readonly HashSet _prims = new HashSet(); private readonly HashSet _activeprims = new HashSet(); + /// + /// Defects list to remove characters that no longer have finite positions due to some other bug. + /// + /// + /// Used repeatedly in Simulate() but initialized once here. + /// + private readonly List defects = new List(); + /// /// Used to lock on manipulation of _taintedPrimL and _taintedPrimH /// @@ -2773,18 +2782,18 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); // Move characters lock (_characters) { - List defects = new List(); foreach (OdeCharacter actor in _characters) { if (actor != null) actor.Move(defects); } + if (0 != defects.Count) { foreach (OdeCharacter defect in defects) - { RemoveCharacter(defect); - } + + defects.Clear(); } } From e0887944a0fe1fa6d695a3dd7ca536ede9968de2 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 17:47:30 +0000 Subject: [PATCH 03/38] Remove unused PhysicsActor.SOPDescription --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 4e79311a61..d2b4fb26ad 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -909,15 +909,7 @@ namespace OpenSim.Region.Framework.Scenes public string Description { get { return m_description; } - set - { - m_description = value; - PhysicsActor actor = PhysActor; - if (actor != null) - { - actor.SOPDescription = value; - } - } + set { m_description = value; } } /// @@ -1543,8 +1535,7 @@ namespace OpenSim.Region.Framework.Scenes // Basic Physics returns null.. joy joy joy. if (PhysActor != null) { - PhysActor.SOPName = this.Name; // save object name and desc into the PhysActor so ODE internals know the joint/body info - PhysActor.SOPDescription = this.Description; + PhysActor.SOPName = this.Name; // save object into the PhysActor so ODE internals know the joint/body info PhysActor.SetMaterial(Material); DoPhysicsPropertyUpdate(RigidBody, true); PhysActor.SetVolumeDetect(VolumeDetectActive ? 1 : 0); From 58a114787096df901d7d8dbf1370089771f91cf3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 17:51:38 +0000 Subject: [PATCH 04/38] refactor: Make SOP.Description an automatic property --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index d2b4fb26ad..b97efc4573 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -242,7 +242,6 @@ namespace OpenSim.Region.Framework.Scenes private byte[] m_TextureAnimation; private byte m_clickAction; private Color m_color = Color.Black; - private string m_description = String.Empty; private readonly List m_lastColliders = new List(); private int m_linkNum; @@ -323,6 +322,7 @@ namespace OpenSim.Region.Framework.Scenes m_TextureAnimation = Utils.EmptyBytes; m_particleSystem = Utils.EmptyBytes; Rezzed = DateTime.UtcNow; + Description = String.Empty; m_inventory = new SceneObjectPartInventory(this); } @@ -342,6 +342,7 @@ namespace OpenSim.Region.Framework.Scenes m_name = "Primitive"; Rezzed = DateTime.UtcNow; + Description = String.Empty; CreationDate = (int)Utils.DateTimeToUnixTime(Rezzed); LastOwnerID = CreatorID = OwnerID = ownerID; UUID = UUID.Random(); @@ -906,11 +907,7 @@ namespace OpenSim.Region.Framework.Scenes set { m_acceleration = value; } } - public string Description - { - get { return m_description; } - set { m_description = value; } - } + public string Description { get; set; } /// /// Text color. From 39c1ae2408f0e93362894b3b45ebc8f965a6d7c5 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 17:55:10 +0000 Subject: [PATCH 05/38] Chain SOP constructors together rather than having copy/paste code --- .../Framework/Scenes/SceneObjectPart.cs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index b97efc4573..24322a174f 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -318,12 +318,14 @@ namespace OpenSim.Region.Framework.Scenes /// public SceneObjectPart() { - // It's not necessary to persist this m_TextureAnimation = Utils.EmptyBytes; m_particleSystem = Utils.EmptyBytes; Rezzed = DateTime.UtcNow; Description = String.Empty; - + + // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol, + // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from + // the prim into an agent inventory (Linden client reports that the "Object not found for drop" in its log m_inventory = new SceneObjectPartInventory(this); } @@ -337,12 +339,10 @@ namespace OpenSim.Region.Framework.Scenes /// public SceneObjectPart( UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition, - Quaternion rotationOffset, Vector3 offsetPosition) + Quaternion rotationOffset, Vector3 offsetPosition) : this() { m_name = "Primitive"; - Rezzed = DateTime.UtcNow; - Description = String.Empty; CreationDate = (int)Utils.DateTimeToUnixTime(Rezzed); LastOwnerID = CreatorID = OwnerID = ownerID; UUID = UUID.Random(); @@ -357,19 +357,10 @@ namespace OpenSim.Region.Framework.Scenes Velocity = Vector3.Zero; AngularVelocity = Vector3.Zero; Acceleration = Vector3.Zero; - m_TextureAnimation = Utils.EmptyBytes; - m_particleSystem = Utils.EmptyBytes; - - // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol, - // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from - // the prim into an agent inventory (Linden client reports that the "Object not found for drop" in its log - Flags = 0; CreateSelected = true; TrimPermissions(); - - m_inventory = new SceneObjectPartInventory(this); } #endregion Constructors From 4fdcfd79e4c8cdbc53fe9a2b46ef7d8511571681 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 17:55:54 +0000 Subject: [PATCH 06/38] Actually remove PhysicsActor.SOPDescription this time --- OpenSim/Region/Physics/Manager/PhysicsActor.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index 798a0a42d9..c213e6ac36 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs @@ -160,8 +160,10 @@ namespace OpenSim.Region.Physics.Manager public abstract bool Selected { set; } + /// + /// This is being used by ODE joint code. + /// public string SOPName; - public string SOPDescription; public abstract void CrossingFailure(); From cead87005bbcb7a4f19440a3bb7876252a7b77ac Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 18:06:04 +0000 Subject: [PATCH 07/38] Have ODECharacter and ODEPrim both use PhysicsActor.Name instead of maintaining their own properties --- OpenSim/Region/Physics/Manager/PhysicsActor.cs | 9 +++++++++ OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | 13 +++++-------- OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 1 - 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index c213e6ac36..c2acf971f9 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs @@ -160,6 +160,15 @@ namespace OpenSim.Region.Physics.Manager public abstract bool Selected { set; } + /// + /// Name of this actor. + /// + /// + /// XXX: Bizarrely, this cannot be "Terrain" or "Water" right now unless it really is simulating terrain or + /// water. This is not a problem due to the formatting of names given by prims and avatars. + /// + public string Name { get; protected set; } + /// /// This is being used by ODE joint code. /// diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index c37d588730..20bc7f646a 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -123,9 +123,6 @@ namespace OpenSim.Region.Physics.OdePlugin private float m_buoyancy = 0f; // private CollisionLocker ode; - - private string m_name = String.Empty; - private bool[] m_colliderarr = new bool[11]; private bool[] m_colliderGroundarr = new bool[11]; @@ -212,7 +209,7 @@ namespace OpenSim.Region.Physics.OdePlugin _parent_scene.AddPhysicsActorTaint(this); - m_name = avName; + Name = avName; } public override int PhysicsActorType @@ -1068,7 +1065,7 @@ namespace OpenSim.Region.Physics.OdePlugin _parent_scene.BadCharacter(this); newPos = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! - m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid); + m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid); } // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) @@ -1284,8 +1281,8 @@ namespace OpenSim.Region.Physics.OdePlugin } AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z, m_tensor); - _parent_scene.geom_name_map[Shell] = m_name; - _parent_scene.actor_name_map[Shell] = (PhysicsActor)this; + _parent_scene.geom_name_map[Shell] = Name; + _parent_scene.actor_name_map[Shell] = this; _parent_scene.AddCharacter(this); } else @@ -1320,7 +1317,7 @@ namespace OpenSim.Region.Physics.OdePlugin // appear to stall initial region crossings when done here. Being done for consistency. // Velocity = Vector3.Zero; - _parent_scene.geom_name_map[Shell] = m_name; + _parent_scene.geom_name_map[Shell] = Name; _parent_scene.actor_name_map[Shell] = (PhysicsActor)this; } else diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 1ba7ef7563..5f21c9db52 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -184,7 +184,6 @@ namespace OpenSim.Region.Physics.OdePlugin private bool m_lastUpdateSent; public IntPtr Body = IntPtr.Zero; - public String Name { get; private set; } private Vector3 _target_velocity; private d.Mass pMass; From 898904d83d371b69d001b669588f29c2befd6aa9 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 18:27:41 +0000 Subject: [PATCH 08/38] When an ODECharacter is removed (e.g. when an avatar leaves a scene), remove the actor reference in OdeScene.actor_name_map rather than leaving it dangling. This also largely centralizes adds/removes in OdeScene.AddCharacter()/RemoveCharacter() --- .../Region/Physics/OdePlugin/ODECharacter.cs | 11 ++-------- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 22 ++++++++++++++++++- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 20bc7f646a..3e7fadf5e3 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -599,13 +599,11 @@ namespace OpenSim.Region.Physics.OdePlugin d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2)); } - d.GeomSetRotation(Shell, ref m_caprot); d.BodySetRotation(Body, ref m_caprot); d.GeomSetBody(Shell, Body); - // The purpose of the AMotor here is to keep the avatar's physical // surrogate from rotating while moving Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); @@ -660,7 +658,6 @@ namespace OpenSim.Region.Physics.OdePlugin //standupStraight(); } - // /// /// Uses the capped cyllinder volume formula to calculate the avatar's mass. /// This may be used in calculations in the scene/scenepresence @@ -1162,14 +1159,12 @@ namespace OpenSim.Region.Physics.OdePlugin { //kill the body d.BodyDestroy(Body); - Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); - _parent_scene.geom_name_map.Remove(Shell); Shell = IntPtr.Zero; } } @@ -1279,10 +1274,8 @@ namespace OpenSim.Region.Physics.OdePlugin + (Body!=IntPtr.Zero ? "Body ":"") + (Amotor!=IntPtr.Zero ? "Amotor ":"")); } + AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z, m_tensor); - - _parent_scene.geom_name_map[Shell] = Name; - _parent_scene.actor_name_map[Shell] = this; _parent_scene.AddCharacter(this); } else @@ -1318,7 +1311,7 @@ namespace OpenSim.Region.Physics.OdePlugin // Velocity = Vector3.Zero; _parent_scene.geom_name_map[Shell] = Name; - _parent_scene.actor_name_map[Shell] = (PhysicsActor)this; + _parent_scene.actor_name_map[Shell] = this; } else { diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index fe2b2b2e5a..9dee07bb5c 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -238,8 +238,23 @@ namespace OpenSim.Region.Physics.OdePlugin private readonly Dictionary _collisionEventPrimChanges = new Dictionary(); private readonly HashSet _badCharacter = new HashSet(); + + /// + /// Maps a unique geometry id (a memory location) to a physics actor name. + /// + /// + /// Only actors participating in collisions have geometries. + /// public Dictionary geom_name_map = new Dictionary(); + + /// + /// Maps a unique geometry id (a memory location) to a physics actor. + /// + /// + /// Only actors participating in collisions have geometries. + /// public Dictionary actor_name_map = new Dictionary(); + private bool m_NINJA_physics_joints_enabled = false; //private Dictionary jointpart_name_map = new Dictionary(); private readonly Dictionary> joints_connecting_actor = new Dictionary>(); @@ -1699,8 +1714,11 @@ namespace OpenSim.Region.Physics.OdePlugin if (!_characters.Contains(chr)) { _characters.Add(chr); + geom_name_map[chr.Shell] = Name; + actor_name_map[chr.Shell] = chr; + if (chr.bad) - m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid); + m_log.ErrorFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid); } } } @@ -1712,6 +1730,8 @@ namespace OpenSim.Region.Physics.OdePlugin if (_characters.Contains(chr)) { _characters.Remove(chr); + geom_name_map.Remove(chr.Shell); + actor_name_map.Remove(chr.Shell); } } } From 4faac1f090b668274e9a07356b8a093d1b662b7e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 19:06:53 +0000 Subject: [PATCH 09/38] When changing avatar size in ODE, remove the old actor from the name and actor maps --- .../Region/Physics/OdePlugin/ODECharacter.cs | 18 +++++++++++------- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 4 +++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 3e7fadf5e3..efe3b7ea03 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -526,7 +526,6 @@ namespace OpenSim.Region.Physics.OdePlugin } } - // movementVector.Z is zero // calculate tilt components based on desired amount of tilt and current (snapped) heading. @@ -1291,16 +1290,21 @@ namespace OpenSim.Region.Physics.OdePlugin { if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero) { -// m_log.DebugFormat("[PHYSICS]: Changing capsule size"); +// m_log.DebugFormat( +// "[ODE CHARACTER]: Changing capsule size from {0} to {1} for {2}", +// CAPSULE_LENGTH, m_tainted_CAPSULE_LENGTH, Name); m_pidControllerActive = true; + + _parent_scene.geom_name_map.Remove(Shell); + _parent_scene.actor_name_map.Remove(Shell); + // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate() - d.JointDestroy(Amotor); + DestroyOdeStructures(); + float prevCapsule = CAPSULE_LENGTH; CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH; - //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString()); - d.BodyDestroy(Body); - d.GeomDestroy(Shell); + AvatarGeomAndBodyCreation( _position.X, _position.Y, @@ -1315,7 +1319,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Warn("[PHYSICS]: trying to change capsule size, but the following ODE data is missing - " + m_log.Warn("[ODE CHARACTER]: trying to change capsule size, but the following ODE data is missing - " + (Shell==IntPtr.Zero ? "Shell ":"") + (Body==IntPtr.Zero ? "Body ":"") + (Amotor==IntPtr.Zero ? "Amotor ":"")); diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 9dee07bb5c..d5c32506a7 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -243,7 +243,9 @@ namespace OpenSim.Region.Physics.OdePlugin /// Maps a unique geometry id (a memory location) to a physics actor name. /// /// - /// Only actors participating in collisions have geometries. + /// Only actors participating in collisions have geometries. This has to be maintained separately from + /// actor_name_map because terrain and water currently don't conceptually have a physics actor of their own + /// apart from the singleton PANull /// public Dictionary geom_name_map = new Dictionary(); From 3becda919e0cb82e29742c50923f1b72c1a02241 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 19:30:21 +0000 Subject: [PATCH 10/38] move geom/actor map maintenance into DestroyODEStructures()/AvatarGeomAndBodyCreation(). This saves us having to do it separately when a character capsule size is changed --- .../Region/Physics/OdePlugin/ODECharacter.cs | 17 +++++++++-------- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 2 -- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index efe3b7ea03..0f1a897f5f 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -655,6 +655,9 @@ namespace OpenSim.Region.Physics.OdePlugin // //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22); //standupStraight(); + + _parent_scene.geom_name_map[Shell] = Name; + _parent_scene.actor_name_map[Shell] = this; } /// @@ -896,7 +899,7 @@ namespace OpenSim.Region.Physics.OdePlugin if (!localPos.IsFinite()) { - m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); + m_log.WarnFormat("[PHYSICS]: Avatar Position of {0} is non-finite!", Name); defects.Add(this); // _parent_scene.RemoveCharacter(this); @@ -1059,9 +1062,10 @@ namespace OpenSim.Region.Physics.OdePlugin { bad = true; _parent_scene.BadCharacter(this); + DestroyOdeStructures(); newPos = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! - m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid); + m_log.WarnFormat("[ODE CHARACTER]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid); } // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) @@ -1164,6 +1168,9 @@ namespace OpenSim.Region.Physics.OdePlugin if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); + _parent_scene.geom_name_map.Remove(Shell); + _parent_scene.actor_name_map.Remove(Shell); + Shell = IntPtr.Zero; } } @@ -1296,9 +1303,6 @@ namespace OpenSim.Region.Physics.OdePlugin m_pidControllerActive = true; - _parent_scene.geom_name_map.Remove(Shell); - _parent_scene.actor_name_map.Remove(Shell); - // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate() DestroyOdeStructures(); @@ -1313,9 +1317,6 @@ namespace OpenSim.Region.Physics.OdePlugin // As with Size, we reset velocity. However, this isn't strictly necessary since it doesn't // appear to stall initial region crossings when done here. Being done for consistency. // Velocity = Vector3.Zero; - - _parent_scene.geom_name_map[Shell] = Name; - _parent_scene.actor_name_map[Shell] = this; } else { diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index d5c32506a7..05455dcaa7 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -1716,8 +1716,6 @@ namespace OpenSim.Region.Physics.OdePlugin if (!_characters.Contains(chr)) { _characters.Add(chr); - geom_name_map[chr.Shell] = Name; - actor_name_map[chr.Shell] = chr; if (chr.bad) m_log.ErrorFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid); From 54789706f40d0800d1277eeb71afd61edcefd9ab Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 19:45:22 +0000 Subject: [PATCH 11/38] Reduce complexity of OdeScene.Simulate() by fully removing bad characters at point of detection rather than later on. --- .../Region/Physics/OdePlugin/ODECharacter.cs | 57 +++++++++---------- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 42 +------------- 2 files changed, 29 insertions(+), 70 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 0f1a897f5f..c838587505 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -178,7 +178,7 @@ namespace OpenSim.Region.Physics.OdePlugin parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f); m_taintPosition = _position; - m_log.Warn("[PHYSICS]: Got NaN Position on Character Create"); + m_log.WarnFormat("[ODE CHARACTER]: Got NaN Position on Character Create for {0}", avName); } _parent_scene = parent_scene; @@ -201,7 +201,7 @@ namespace OpenSim.Region.Physics.OdePlugin m_colliderarr[i] = false; } CAPSULE_LENGTH = (size.Z * 1.15f) - CAPSULE_RADIUS * 2.0f; - //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString()); + //m_log.Info("[ODE CHARACTER]: " + CAPSULE_LENGTH.ToString()); m_tainted_CAPSULE_LENGTH = CAPSULE_LENGTH; m_isPhysical = false; // current status: no ODE information exists @@ -266,7 +266,7 @@ namespace OpenSim.Region.Physics.OdePlugin set { flying = value; -// m_log.DebugFormat("[PHYSICS]: Set OdeCharacter Flying to {0}", flying); +// m_log.DebugFormat("[ODE CHARACTER]: Set OdeCharacter Flying to {0}", flying); } } @@ -437,7 +437,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Warn("[PHYSICS]: Got a NaN Position from Scene on a Character"); + m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Position from Scene on character {0}", Name); } } } @@ -464,7 +464,7 @@ namespace OpenSim.Region.Physics.OdePlugin Vector3 SetSize = value; m_tainted_CAPSULE_LENGTH = (SetSize.Z * 1.15f) - CAPSULE_RADIUS * 2.0f; -// m_log.Info("[SIZE]: " + CAPSULE_LENGTH); +// m_log.Info("[ODE CHARACTER]: " + CAPSULE_LENGTH); // If we reset velocity here, then an avatar stalls when it crosses a border for the first time // (as the height of the new root agent is set). @@ -474,7 +474,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Warn("[PHYSICS]: Got a NaN Size from Scene on a Character"); + m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Size from Scene on {0}", Name); } } } @@ -533,7 +533,7 @@ namespace OpenSim.Region.Physics.OdePlugin float xTiltComponent = -movementVector.X * m_tiltMagnitudeWhenProjectedOnXYPlane; float yTiltComponent = -movementVector.Y * m_tiltMagnitudeWhenProjectedOnXYPlane; - //m_log.Debug("[PHYSICS] changing avatar tilt"); + //m_log.Debug("[ODE CHARACTER]: changing avatar tilt"); d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, xTiltComponent); d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, xTiltComponent); // must be same as lowstop, else a different, spurious tilt is introduced d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, yTiltComponent); @@ -560,17 +560,16 @@ namespace OpenSim.Region.Physics.OdePlugin _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (CAPSULE_LENGTH <= 0) { - m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); + m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); CAPSULE_LENGTH = 0.01f; - } if (CAPSULE_RADIUS <= 0) { - m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); + m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); CAPSULE_RADIUS = 0.01f; - } + Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH); d.GeomSetCategoryBits(Shell, (int)m_collisionCategories); @@ -770,7 +769,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Warn("[PHYSICS]: Got a NaN velocity from Scene in a Character"); + m_log.WarnFormat("[ODE CHARACTER]: Got a NaN velocity from Scene for {0}", Name); } // m_log.DebugFormat("[PHYSICS]: Set target velocity of {0}", m_taintTargetVelocity); @@ -848,7 +847,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Warn("[PHYSICS]: Got a NaN force applied to a Character"); + m_log.WarnFormat("[ODE CHARACTER]: Got a NaN force applied to {0}", Name); } //m_lastUpdateSent = false; } @@ -874,11 +873,11 @@ namespace OpenSim.Region.Physics.OdePlugin /// Called from Simulate /// This is the avatar's movement control + PID Controller /// - /// - /// If there is something wrong with the character (e.g. its position is non-finite) - /// then it is added to this list. The ODE structures associated with it are also destroyed. - /// - internal void Move(List defects) + /// + /// This routine will remove the character from the physics scene if it detects something wrong (non-finite + /// position or velocity). + /// + internal void Move() { // no lock; for now it's only called from within Simulate() @@ -899,11 +898,11 @@ namespace OpenSim.Region.Physics.OdePlugin if (!localPos.IsFinite()) { - m_log.WarnFormat("[PHYSICS]: Avatar Position of {0} is non-finite!", Name); - - defects.Add(this); - // _parent_scene.RemoveCharacter(this); + m_log.WarnFormat( + "[ODE CHARACTER]: Avatar position of {0} for {1} is non-finite! Removing from physics scene.", + localPos, Name); + _parent_scene.RemoveCharacter(this); DestroyOdeStructures(); return; @@ -1038,11 +1037,11 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Warn("[PHYSICS]: Got a NaN force vector in Move()"); - m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); - defects.Add(this); - // _parent_scene.RemoveCharacter(this); + m_log.WarnFormat( + "[ODE CHARACTER]: Got a NaN force vector {0} in Move() for {1}. Removing character from physics scene.", + vec, Name); + _parent_scene.RemoveCharacter(this); DestroyOdeStructures(); } } @@ -1061,7 +1060,7 @@ namespace OpenSim.Region.Physics.OdePlugin catch (NullReferenceException) { bad = true; - _parent_scene.BadCharacter(this); + _parent_scene.RemoveCharacter(this); DestroyOdeStructures(); newPos = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! @@ -1275,7 +1274,7 @@ namespace OpenSim.Region.Physics.OdePlugin // Create avatar capsule and related ODE data if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero)) { - m_log.Warn("[PHYSICS]: re-creating the following avatar ODE data, even though it already exists - " + m_log.Warn("[ODE CHARACTER]: re-creating the following avatar ODE data for " + Name + ", even though it already exists - " + (Shell!=IntPtr.Zero ? "Shell ":"") + (Body!=IntPtr.Zero ? "Body ":"") + (Amotor!=IntPtr.Zero ? "Amotor ":"")); @@ -1320,7 +1319,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Warn("[ODE CHARACTER]: trying to change capsule size, but the following ODE data is missing - " + m_log.Warn("[ODE CHARACTER]: trying to change capsule size for " + Name + ", but the following ODE data is missing - " + (Shell==IntPtr.Zero ? "Shell ":"") + (Body==IntPtr.Zero ? "Body ":"") + (Amotor==IntPtr.Zero ? "Amotor ":"")); diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 05455dcaa7..9c3c07788d 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -193,14 +193,6 @@ namespace OpenSim.Region.Physics.OdePlugin private readonly HashSet _prims = new HashSet(); private readonly HashSet _activeprims = new HashSet(); - /// - /// Defects list to remove characters that no longer have finite positions due to some other bug. - /// - /// - /// Used repeatedly in Simulate() but initialized once here. - /// - private readonly List defects = new List(); - /// /// Used to lock on manipulation of _taintedPrimL and _taintedPrimH /// @@ -236,8 +228,6 @@ namespace OpenSim.Region.Physics.OdePlugin /// A dictionary of collision event changes that are waiting to be processed. /// private readonly Dictionary _collisionEventPrimChanges = new Dictionary(); - - private readonly HashSet _badCharacter = new HashSet(); /// /// Maps a unique geometry id (a memory location) to a physics actor name. @@ -1736,15 +1726,6 @@ namespace OpenSim.Region.Physics.OdePlugin } } - internal void BadCharacter(OdeCharacter chr) - { - lock (_badCharacter) - { - if (!_badCharacter.Contains(chr)) - _badCharacter.Add(chr); - } - } - private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, PrimitiveBaseShape pbs, bool isphysical, uint localID) { @@ -2805,15 +2786,7 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); foreach (OdeCharacter actor in _characters) { if (actor != null) - actor.Move(defects); - } - - if (0 != defects.Count) - { - foreach (OdeCharacter defect in defects) - RemoveCharacter(defect); - - defects.Clear(); + actor.Move(); } } @@ -2885,19 +2858,6 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); } } - lock (_badCharacter) - { - if (_badCharacter.Count > 0) - { - foreach (OdeCharacter chr in _badCharacter) - { - RemoveCharacter(chr); - } - - _badCharacter.Clear(); - } - } - lock (_activeprims) { //if (timeStep < 0.2f) From 225b925f4ec6a0b7dfec27589d0aea40ce0a8e54 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 19:48:31 +0000 Subject: [PATCH 12/38] Comment out calls to OdeScene.waitForSpaceUnlock() since that method does nothing right now --- .../Region/Physics/OdePlugin/ODECharacter.cs | 4 +-- OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 18 ++++++------- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 25 ++++++++++--------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index c838587505..af67407629 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -557,7 +557,7 @@ namespace OpenSim.Region.Physics.OdePlugin //CAPSULE_LENGTH = -5; //CAPSULE_RADIUS = -5; int dAMotorEuler = 1; - _parent_scene.waitForSpaceUnlock(_parent_scene.space); +// _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (CAPSULE_LENGTH <= 0) { m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); @@ -1155,7 +1155,7 @@ namespace OpenSim.Region.Physics.OdePlugin } //kill the Geometry - _parent_scene.waitForSpaceUnlock(_parent_scene.space); +// _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (Body != IntPtr.Zero) { diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 5f21c9db52..fec46939f5 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -856,7 +856,7 @@ namespace OpenSim.Region.Physics.OdePlugin m_MeshToTriMeshMap[mesh] = _triMeshData; } - _parent_scene.waitForSpaceUnlock(m_targetSpace); +// _parent_scene.waitForSpaceUnlock(m_targetSpace); try { if (prim_geom == IntPtr.Zero) @@ -1379,7 +1379,7 @@ Console.WriteLine("CreateGeom:"); { if (((_size.X / 2f) > 0f)) { - _parent_scene.waitForSpaceUnlock(m_targetSpace); +// _parent_scene.waitForSpaceUnlock(m_targetSpace); try { //Console.WriteLine(" CreateGeom 1"); @@ -1393,7 +1393,7 @@ Console.WriteLine("CreateGeom:"); } else { - _parent_scene.waitForSpaceUnlock(m_targetSpace); +// _parent_scene.waitForSpaceUnlock(m_targetSpace); try { //Console.WriteLine(" CreateGeom 2"); @@ -1408,7 +1408,7 @@ Console.WriteLine("CreateGeom:"); } else { - _parent_scene.waitForSpaceUnlock(m_targetSpace); +// _parent_scene.waitForSpaceUnlock(m_targetSpace); try { //Console.WriteLine(" CreateGeom 3"); @@ -1423,7 +1423,7 @@ Console.WriteLine("CreateGeom:"); } else { - _parent_scene.waitForSpaceUnlock(m_targetSpace); +// _parent_scene.waitForSpaceUnlock(m_targetSpace); try { //Console.WriteLine(" CreateGeom 4"); @@ -1576,17 +1576,17 @@ Console.WriteLine(" JointCreateFixed"); { // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position); // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position); - _parent_scene.waitForSpaceUnlock(m_targetSpace); +// _parent_scene.waitForSpaceUnlock(m_targetSpace); IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace); m_targetSpace = tempspace; - _parent_scene.waitForSpaceUnlock(m_targetSpace); +// _parent_scene.waitForSpaceUnlock(m_targetSpace); if (prim_geom != IntPtr.Zero) { d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); - _parent_scene.waitForSpaceUnlock(m_targetSpace); +// _parent_scene.waitForSpaceUnlock(m_targetSpace); d.SpaceAdd(m_targetSpace, prim_geom); } } @@ -1977,7 +1977,7 @@ Console.WriteLine(" JointCreateFixed"); if (d.SpaceQuery(m_targetSpace, prim_geom)) { - _parent_scene.waitForSpaceUnlock(m_targetSpace); +// _parent_scene.waitForSpaceUnlock(m_targetSpace); d.SpaceRemove(m_targetSpace, prim_geom); } diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 9c3c07788d..b952b306d3 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -679,11 +679,11 @@ namespace OpenSim.Region.Physics.OdePlugin } } - internal void waitForSpaceUnlock(IntPtr space) - { - //if (space != IntPtr.Zero) - //while (d.SpaceLockQuery(space)) { } // Wait and do nothing - } +// internal void waitForSpaceUnlock(IntPtr space) +// { +// //if (space != IntPtr.Zero) +// //while (d.SpaceLockQuery(space)) { } // Wait and do nothing +// } // /// // /// Debug space message for printing the space that a prim/avatar is in. @@ -2303,7 +2303,7 @@ namespace OpenSim.Region.Physics.OdePlugin { if (d.GeomIsSpace(currentspace)) { - waitForSpaceUnlock(currentspace); +// waitForSpaceUnlock(currentspace); d.SpaceRemove(currentspace, geom); } else @@ -2319,7 +2319,7 @@ namespace OpenSim.Region.Physics.OdePlugin { if (d.GeomIsSpace(currentspace)) { - waitForSpaceUnlock(sGeomIsIn); +// waitForSpaceUnlock(sGeomIsIn); d.SpaceRemove(sGeomIsIn, geom); } else @@ -2337,8 +2337,8 @@ namespace OpenSim.Region.Physics.OdePlugin { if (d.GeomIsSpace(currentspace)) { - waitForSpaceUnlock(currentspace); - waitForSpaceUnlock(space); +// waitForSpaceUnlock(currentspace); +// waitForSpaceUnlock(space); d.SpaceRemove(space, currentspace); // free up memory used by the space. @@ -2362,7 +2362,7 @@ namespace OpenSim.Region.Physics.OdePlugin { if (d.GeomIsSpace(currentspace)) { - waitForSpaceUnlock(currentspace); +// waitForSpaceUnlock(currentspace); d.SpaceRemove(currentspace, geom); } else @@ -2378,7 +2378,7 @@ namespace OpenSim.Region.Physics.OdePlugin { if (d.GeomIsSpace(sGeomIsIn)) { - waitForSpaceUnlock(sGeomIsIn); +// waitForSpaceUnlock(sGeomIsIn); d.SpaceRemove(sGeomIsIn, geom); } else @@ -2417,9 +2417,10 @@ namespace OpenSim.Region.Physics.OdePlugin // creating a new space for prim and inserting it into main space. staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero); d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space); - waitForSpaceUnlock(space); +// waitForSpaceUnlock(space); d.SpaceSetSublevel(space, 1); d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]); + return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]; } From 063f0f5d97d8b8d38a57c7a0601e9133d0054a26 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 19:58:37 +0000 Subject: [PATCH 13/38] refactor: Eliminate one line ODECharacter.doForce() method for code clarity --- .../Region/Physics/OdePlugin/ODECharacter.cs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index af67407629..afa8de5870 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -70,7 +70,6 @@ namespace OpenSim.Region.Physics.OdePlugin private Vector3 _position; private d.Vector3 _zeroPosition; - // private d.Matrix3 m_StandUpRotation; private bool _zeroFlag = false; private bool m_lastUpdateSent = false; private Vector3 _velocity; @@ -554,8 +553,6 @@ namespace OpenSim.Region.Physics.OdePlugin // place that is safe to call this routine AvatarGeomAndBodyCreation. private void AvatarGeomAndBodyCreation(float npositionX, float npositionY, float npositionZ, float tensor) { - //CAPSULE_LENGTH = -5; - //CAPSULE_RADIUS = -5; int dAMotorEuler = 1; // _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (CAPSULE_LENGTH <= 0) @@ -831,7 +828,6 @@ namespace OpenSim.Region.Physics.OdePlugin m_taintForce += force; _parent_scene.AddPhysicsActorTaint(this); - //doForce(force); // If uncommented, things get pushed off world // // m_log.Debug("Push!"); @@ -856,15 +852,6 @@ namespace OpenSim.Region.Physics.OdePlugin { } - /// - /// After all of the forces add up with 'add force' we apply them with doForce - /// - /// - public void doForce(Vector3 force) - { - d.BodyAddForce(Body, force.X, force.Y, force.Z); - } - public override void SetMomentum(Vector3 momentum) { } @@ -1030,7 +1017,8 @@ namespace OpenSim.Region.Physics.OdePlugin if (vec.IsFinite()) { - doForce(vec); + // Apply the total force acting on this avatar + d.BodyAddForce(Body, vec.X, vec.Y, vec.Z); if (!_zeroFlag) AlignAvatarTiltWithCurrentDirectionOfMovement(vec); @@ -1258,7 +1246,7 @@ namespace OpenSim.Region.Physics.OdePlugin // FIXME: This is not a good solution since it's subject to a race condition if a force is another // thread sets a new force while we're in this loop (since it could be obliterated by // m_taintForce = Vector3.Zero. Need to lock ProcessTaints() when we set a new tainted force. - doForce(m_taintForce); + d.BodyAddForce(Body, m_taintForce.X, m_taintForce.Y, m_taintForce.Z); } m_taintForce = Vector3.Zero; From e67ba0ad06a0ff54834892257d8e7bc39b4fc892 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 20:01:34 +0000 Subject: [PATCH 14/38] rename ODECharacter.AvatarGeomAndBodyCreation() -> CreateOdeStructures() to match existing DestroyOdeStructures() --- .../Region/Physics/OdePlugin/ODECharacter.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index afa8de5870..5a7626e9d7 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -542,16 +542,18 @@ namespace OpenSim.Region.Physics.OdePlugin } /// - /// This creates the Avatar's physical Surrogate at the position supplied + /// This creates the Avatar's physical Surrogate in ODE at the position supplied /// + /// + /// WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access + /// to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only + /// place that is safe to call this routine AvatarGeomAndBodyCreation. + /// /// /// /// - - // WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access - // to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only - // place that is safe to call this routine AvatarGeomAndBodyCreation. - private void AvatarGeomAndBodyCreation(float npositionX, float npositionY, float npositionZ, float tensor) + /// + private void CreateOdeStructures(float npositionX, float npositionY, float npositionZ, float tensor) { int dAMotorEuler = 1; // _parent_scene.waitForSpaceUnlock(_parent_scene.space); @@ -1268,7 +1270,7 @@ namespace OpenSim.Region.Physics.OdePlugin + (Amotor!=IntPtr.Zero ? "Amotor ":"")); } - AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z, m_tensor); + CreateOdeStructures(_position.X, _position.Y, _position.Z, m_tensor); _parent_scene.AddCharacter(this); } else @@ -1296,7 +1298,7 @@ namespace OpenSim.Region.Physics.OdePlugin float prevCapsule = CAPSULE_LENGTH; CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH; - AvatarGeomAndBodyCreation( + CreateOdeStructures( _position.X, _position.Y, _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor); From e33b0fa35bf6bef47849c82b1ef1f5f81420217e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 20:12:04 +0000 Subject: [PATCH 15/38] don't lock OdeScene.contacts since only ever accessed by a single thread --- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 34 ++++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index b952b306d3..92dd2dd05b 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -251,10 +251,27 @@ namespace OpenSim.Region.Physics.OdePlugin //private Dictionary jointpart_name_map = new Dictionary(); private readonly Dictionary> joints_connecting_actor = new Dictionary>(); private d.ContactGeom[] contacts; - private readonly List requestedJointsToBeCreated = new List(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active - private readonly List pendingJoints = new List(); // can lock for longer. accessed only by OdeScene. - private readonly List activeJoints = new List(); // can lock for longer. accessed only by OdeScene. - private readonly List requestedJointsToBeDeleted = new List(); // lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active + + /// + /// Lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active + /// + private readonly List requestedJointsToBeCreated = new List(); + + /// + /// can lock for longer. accessed only by OdeScene. + /// + private readonly List pendingJoints = new List(); + + /// + /// can lock for longer. accessed only by OdeScene. + /// + private readonly List activeJoints = new List(); + + /// + /// lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active + /// + private readonly List requestedJointsToBeDeleted = new List(); + private Object externalJointRequestsLock = new Object(); private readonly Dictionary SOPName_to_activeJoint = new Dictionary(); private readonly Dictionary SOPName_to_pendingJoint = new Dictionary(); @@ -776,12 +793,9 @@ namespace OpenSim.Region.Physics.OdePlugin if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) return; - lock (contacts) - { - count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf); - if (count > contacts.Length) - m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); - } + count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf); + if (count > contacts.Length) + m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); } catch (SEHException) { From 25d9001de1225a7d1c938f440b43c37bcca0e69e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 20:17:36 +0000 Subject: [PATCH 16/38] don't bother locking OdeScene._perloopContact in single threaded code --- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 95 ++++++++++---------- 1 file changed, 45 insertions(+), 50 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 92dd2dd05b..897ab82f7d 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -1247,69 +1247,64 @@ namespace OpenSim.Region.Physics.OdePlugin private bool checkDupe(d.ContactGeom contactGeom, int atype) { - bool result = false; - //return result; if (!m_filterCollisions) return false; + + bool result = false; ActorTypes at = (ActorTypes)atype; - lock (_perloopContact) + + foreach (d.ContactGeom contact in _perloopContact) { - foreach (d.ContactGeom contact in _perloopContact) + //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2)) + //{ + // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2) + if (at == ActorTypes.Agent) { - //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2)) - //{ - // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2) - if (at == ActorTypes.Agent) - { - if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom) + if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom) + { + + if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) { - - if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) - { - //contactGeom.depth *= .00005f; - //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); - // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); - result = true; - break; - } - else - { - //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); - } + //contactGeom.depth *= .00005f; + //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); + // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); + result = true; + break; } else { - //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); - //int i = 0; - } - } - else if (at == ActorTypes.Prim) - { - //d.AABB aabb1 = new d.AABB(); - //d.AABB aabb2 = new d.AABB(); - - //d.GeomGetAABB(contactGeom.g2, out aabb2); - //d.GeomGetAABB(contactGeom.g1, out aabb1); - //aabb1. - if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom) - { - if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z) - { - if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f) - { - result = true; - break; - } - } //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); - //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); } - - } - - //} + } + else + { + //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); + //int i = 0; + } + } + else if (at == ActorTypes.Prim) + { + //d.AABB aabb1 = new d.AABB(); + //d.AABB aabb2 = new d.AABB(); + //d.GeomGetAABB(contactGeom.g2, out aabb2); + //d.GeomGetAABB(contactGeom.g1, out aabb1); + //aabb1. + if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom) + { + if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z) + { + if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f) + { + result = true; + break; + } + } + //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); + //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); + } + } } From 546259b2ffdb7dfdc450dd5386ec6794bb06223d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 20:30:37 +0000 Subject: [PATCH 17/38] simplify operation of OdeScene._perloopContact --- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 96 +++++++++++--------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 897ab82f7d..7db188f289 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -216,7 +216,14 @@ namespace OpenSim.Region.Physics.OdePlugin /// private readonly HashSet _taintedPrimH = new HashSet(); + /// + /// Record a character that has taints to be processed. + /// private readonly HashSet _taintedActors = new HashSet(); + + /// + /// Keep record of contacts in the physics loop so that we can remove duplicates. + /// private readonly List _perloopContact = new List(); /// @@ -1059,6 +1066,8 @@ namespace OpenSim.Region.Physics.OdePlugin if (!skipThisContact) { + _perloopContact.Add(curContact); + // If we're colliding against terrain if (name1 == "Terrain" || name2 == "Terrain") { @@ -1068,7 +1077,7 @@ namespace OpenSim.Region.Physics.OdePlugin { // Use the movement terrain contact AvatarMovementTerrainContact.geom = curContact; - _perloopContact.Add(curContact); + if (m_global_contactcount < maxContactsbeforedeath) { joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); @@ -1081,7 +1090,7 @@ namespace OpenSim.Region.Physics.OdePlugin { // Use the non moving terrain contact TerrainContact.geom = curContact; - _perloopContact.Add(curContact); + if (m_global_contactcount < maxContactsbeforedeath) { joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); @@ -1107,7 +1116,6 @@ namespace OpenSim.Region.Physics.OdePlugin //m_log.DebugFormat("Material: {0}", material); m_materialContacts[material, movintYN].geom = curContact; - _perloopContact.Add(curContact); if (m_global_contactcount < maxContactsbeforedeath) { @@ -1128,9 +1136,9 @@ namespace OpenSim.Region.Physics.OdePlugin if (p2 is OdePrim) material = ((OdePrim)p2).m_material; + //m_log.DebugFormat("Material: {0}", material); m_materialContacts[material, movintYN].geom = curContact; - _perloopContact.Add(curContact); if (m_global_contactcount < maxContactsbeforedeath) { @@ -1163,8 +1171,9 @@ namespace OpenSim.Region.Physics.OdePlugin //contact.normal = new d.Vector3(0, 0, 1); //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f); } + WaterContact.geom = curContact; - _perloopContact.Add(curContact); + if (m_global_contactcount < maxContactsbeforedeath) { joint = d.JointCreateContact(world, contactgroup, ref WaterContact); @@ -1182,7 +1191,7 @@ namespace OpenSim.Region.Physics.OdePlugin { // Use the Movement prim contact AvatarMovementprimContact.geom = curContact; - _perloopContact.Add(curContact); + if (m_global_contactcount < maxContactsbeforedeath) { joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); @@ -1212,13 +1221,11 @@ namespace OpenSim.Region.Physics.OdePlugin //m_log.DebugFormat("Material: {0}", material); m_materialContacts[material, 0].geom = curContact; - _perloopContact.Add(curContact); if (m_global_contactcount < maxContactsbeforedeath) { joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]); m_global_contactcount++; - } } } @@ -1249,7 +1256,7 @@ namespace OpenSim.Region.Physics.OdePlugin { if (!m_filterCollisions) return false; - + bool result = false; ActorTypes at = (ActorTypes)atype; @@ -1261,50 +1268,51 @@ namespace OpenSim.Region.Physics.OdePlugin // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2) if (at == ActorTypes.Agent) { - if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom) + if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) + && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) + && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) + && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom) + { + if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) { - - if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) - { - //contactGeom.depth *= .00005f; - //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); - // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); - result = true; - break; - } - else - { - //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); - } - } - else - { - //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); - //int i = 0; + //contactGeom.depth *= .00005f; + //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); + // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); + result = true; + break; } +// else +// { +// //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); +// } + } +// else +// { +// //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); +// //int i = 0; +// } } else if (at == ActorTypes.Prim) { - //d.AABB aabb1 = new d.AABB(); - //d.AABB aabb2 = new d.AABB(); + //d.AABB aabb1 = new d.AABB(); + //d.AABB aabb2 = new d.AABB(); - //d.GeomGetAABB(contactGeom.g2, out aabb2); - //d.GeomGetAABB(contactGeom.g1, out aabb1); - //aabb1. - if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom) + //d.GeomGetAABB(contactGeom.g2, out aabb2); + //d.GeomGetAABB(contactGeom.g1, out aabb1); + //aabb1. + if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom) + { + if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z) { - if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z) + if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f) { - if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f) - { - result = true; - break; - } + result = true; + break; } - //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); - //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); } - + //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); + //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); + } } } @@ -1589,8 +1597,6 @@ namespace OpenSim.Region.Physics.OdePlugin } } } - - _perloopContact.Clear(); } #endregion From 7480f2fd0e5482d366890b34d4aca72c887e02c3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 21:04:24 +0000 Subject: [PATCH 18/38] Restore defects list. In hindsight, the reason for this is becuase we can't remove the character whilst iterating over the list. This commit also removes locking on OdeScene._characters since code is single threaded --- .../Region/Physics/OdePlugin/ODECharacter.cs | 27 +-- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 177 ++++++++++-------- 2 files changed, 112 insertions(+), 92 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 5a7626e9d7..cfe64f2781 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -862,11 +862,10 @@ namespace OpenSim.Region.Physics.OdePlugin /// Called from Simulate /// This is the avatar's movement control + PID Controller /// - /// - /// This routine will remove the character from the physics scene if it detects something wrong (non-finite + /// The character will be added to this list if there is something wrong (non-finite /// position or velocity). - /// - internal void Move() + /// + internal void Move(List defects) { // no lock; for now it's only called from within Simulate() @@ -891,8 +890,7 @@ namespace OpenSim.Region.Physics.OdePlugin "[ODE CHARACTER]: Avatar position of {0} for {1} is non-finite! Removing from physics scene.", localPos, Name); - _parent_scene.RemoveCharacter(this); - DestroyOdeStructures(); + defects.Add(this); return; } @@ -1031,15 +1029,19 @@ namespace OpenSim.Region.Physics.OdePlugin "[ODE CHARACTER]: Got a NaN force vector {0} in Move() for {1}. Removing character from physics scene.", vec, Name); - _parent_scene.RemoveCharacter(this); - DestroyOdeStructures(); + defects.Add(this); + + return; } } /// /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. /// - internal void UpdatePositionAndVelocity() + /// The character will be added to this list if there is something wrong (non-finite + /// position or velocity). + /// + internal void UpdatePositionAndVelocity(List defects) { // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! d.Vector3 newPos; @@ -1050,11 +1052,12 @@ namespace OpenSim.Region.Physics.OdePlugin catch (NullReferenceException) { bad = true; - _parent_scene.RemoveCharacter(this); - DestroyOdeStructures(); + defects.Add(this); newPos = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! m_log.WarnFormat("[ODE CHARACTER]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid); + + return; } // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) @@ -1134,7 +1137,7 @@ namespace OpenSim.Region.Physics.OdePlugin /// /// Used internally to destroy the ODE structures associated with this character. /// - private void DestroyOdeStructures() + internal void DestroyOdeStructures() { // destroy avatar capsule and related ODE data if (Amotor != IntPtr.Zero) diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 7db188f289..89568b676d 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -189,7 +189,11 @@ namespace OpenSim.Region.Physics.OdePlugin public d.TriCallback triCallback; public d.TriArrayCallback triArrayCallback; + /// + /// Avatars in the physics scene. + /// private readonly HashSet _characters = new HashSet(); + private readonly HashSet _prims = new HashSet(); private readonly HashSet _activeprims = new HashSet(); @@ -254,6 +258,14 @@ namespace OpenSim.Region.Physics.OdePlugin /// public Dictionary actor_name_map = new Dictionary(); + /// + /// Defects list to remove characters that no longer have finite positions due to some other bug. + /// + /// + /// Used repeatedly in Simulate() but initialized once here. + /// + private readonly List defects = new List(); + private bool m_NINJA_physics_joints_enabled = false; //private Dictionary jointpart_name_map = new Dictionary(); private readonly Dictionary> joints_connecting_actor = new Dictionary>(); @@ -1515,45 +1527,42 @@ namespace OpenSim.Region.Physics.OdePlugin { _perloopContact.Clear(); - lock (_characters) + foreach (OdeCharacter chr in _characters) { - foreach (OdeCharacter chr in _characters) + // Reset the collision values to false + // since we don't know if we're colliding yet + + // For some reason this can happen. Don't ask... + // + if (chr == null) + continue; + + if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero) + continue; + + chr.IsColliding = false; + chr.CollidingGround = false; + chr.CollidingObj = false; + + // test the avatar's geometry for collision with the space + // This will return near and the space that they are the closest to + // And we'll run this again against the avatar and the space segment + // This will return with a bunch of possible objects in the space segment + // and we'll run it again on all of them. + try { - // Reset the collision values to false - // since we don't know if we're colliding yet - - // For some reason this can happen. Don't ask... - // - if (chr == null) - continue; - - if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero) - continue; - - chr.IsColliding = false; - chr.CollidingGround = false; - chr.CollidingObj = false; - - // test the avatar's geometry for collision with the space - // This will return near and the space that they are the closest to - // And we'll run this again against the avatar and the space segment - // This will return with a bunch of possible objects in the space segment - // and we'll run it again on all of them. - try - { - d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback); - } - catch (AccessViolationException) - { - m_log.Warn("[PHYSICS]: Unable to space collide"); - } - //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y); - //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10) - //{ - //chr.Position.Z = terrainheight + 10.0f; - //forcedZ = true; - //} + d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback); } + catch (AccessViolationException) + { + m_log.Warn("[PHYSICS]: Unable to space collide"); + } + //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y); + //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10) + //{ + //chr.Position.Z = terrainheight + 10.0f; + //forcedZ = true; + //} } lock (_activeprims) @@ -1716,28 +1725,22 @@ namespace OpenSim.Region.Physics.OdePlugin internal void AddCharacter(OdeCharacter chr) { - lock (_characters) + if (!_characters.Contains(chr)) { - if (!_characters.Contains(chr)) - { - _characters.Add(chr); + _characters.Add(chr); - if (chr.bad) - m_log.ErrorFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid); - } + if (chr.bad) + m_log.ErrorFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid); } } internal void RemoveCharacter(OdeCharacter chr) { - lock (_characters) + if (_characters.Contains(chr)) { - if (_characters.Contains(chr)) - { - _characters.Remove(chr); - geom_name_map.Remove(chr.Shell); - actor_name_map.Remove(chr.Shell); - } + _characters.Remove(chr); + geom_name_map.Remove(chr.Shell); + actor_name_map.Remove(chr.Shell); } } @@ -2797,13 +2800,21 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); } // Move characters - lock (_characters) + foreach (OdeCharacter actor in _characters) { - foreach (OdeCharacter actor in _characters) + if (actor != null) + actor.Move(defects); + } + + if (defects.Count != 0) + { + foreach (OdeCharacter actor in defects) { - if (actor != null) - actor.Move(); + RemoveCharacter(actor); + actor.DestroyOdeStructures(); } + + defects.Clear(); } // Move other active objects @@ -2860,20 +2871,28 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); timeLeft -= ODE_STEPSIZE; } - lock (_characters) + foreach (OdeCharacter actor in _characters) { - foreach (OdeCharacter actor in _characters) + if (actor != null) { - if (actor != null) - { - if (actor.bad) - m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); + if (actor.bad) + m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); - actor.UpdatePositionAndVelocity(); - } + actor.UpdatePositionAndVelocity(defects); } } + if (defects.Count != 0) + { + foreach (OdeCharacter actor in defects) + { + RemoveCharacter(actor); + actor.DestroyOdeStructures(); + } + + defects.Clear(); + } + lock (_activeprims) { //if (timeStep < 0.2f) @@ -3899,30 +3918,28 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); } } ds.SetColor(1.0f, 0.0f, 0.0f); - lock (_characters) + + foreach (OdeCharacter chr in _characters) { - foreach (OdeCharacter chr in _characters) + if (chr.Shell != IntPtr.Zero) { - if (chr.Shell != IntPtr.Zero) - { - IntPtr body = d.GeomGetBody(chr.Shell); + IntPtr body = d.GeomGetBody(chr.Shell); - d.Vector3 pos; - d.GeomCopyPosition(chr.Shell, out pos); - //d.BodyCopyPosition(body, out pos); + d.Vector3 pos; + d.GeomCopyPosition(chr.Shell, out pos); + //d.BodyCopyPosition(body, out pos); - d.Matrix3 R; - d.GeomCopyRotation(chr.Shell, out R); - //d.BodyCopyRotation(body, out R); + d.Matrix3 R; + d.GeomCopyRotation(chr.Shell, out R); + //d.BodyCopyRotation(body, out R); - ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f); - d.Vector3 sides = new d.Vector3(); - sides.X = 0.5f; - sides.Y = 0.5f; - sides.Z = 0.5f; + ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f); + d.Vector3 sides = new d.Vector3(); + sides.X = 0.5f; + sides.Y = 0.5f; + sides.Z = 0.5f; - ds.DrawBox(ref pos, ref R, ref sides); - } + ds.DrawBox(ref pos, ref R, ref sides); } } } From 82dc7886fc8e7517530077a593d352939f7a29d2 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 21:15:15 +0000 Subject: [PATCH 19/38] remove unnecessary OdeScene._activeprims locking. Code is single-threaded --- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 103 +++++++++---------- 1 file changed, 48 insertions(+), 55 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 89568b676d..d1c1c25e44 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -193,8 +193,15 @@ namespace OpenSim.Region.Physics.OdePlugin /// Avatars in the physics scene. /// private readonly HashSet _characters = new HashSet(); - + + /// + /// Prims in the physics scene. + /// private readonly HashSet _prims = new HashSet(); + + /// + /// Prims in the physics scene that are subject to physics, not just collisions. + /// private readonly HashSet _activeprims = new HashSet(); /// @@ -1565,45 +1572,42 @@ namespace OpenSim.Region.Physics.OdePlugin //} } - lock (_activeprims) + List removeprims = null; + foreach (OdePrim chr in _activeprims) { - List removeprims = null; - foreach (OdePrim chr in _activeprims) + if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled)) { - if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled)) + try { - try + lock (chr) { - lock (chr) + if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false) { - if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false) + d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback); + } + else + { + if (removeprims == null) { - d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback); - } - else - { - if (removeprims == null) - { - removeprims = new List(); - } - removeprims.Add(chr); - m_log.Debug("[PHYSICS]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!"); + removeprims = new List(); } + removeprims.Add(chr); + m_log.Debug("[PHYSICS]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!"); } } - catch (AccessViolationException) - { - m_log.Warn("[PHYSICS]: Unable to space collide"); - } + } + catch (AccessViolationException) + { + m_log.Warn("[PHYSICS]: Unable to space collide"); } } + } - if (removeprims != null) + if (removeprims != null) + { + foreach (OdePrim chr in removeprims) { - foreach (OdePrim chr in removeprims) - { - _activeprims.Remove(chr); - } + _activeprims.Remove(chr); } } } @@ -1770,13 +1774,10 @@ namespace OpenSim.Region.Physics.OdePlugin internal void ActivatePrim(OdePrim prim) { // adds active prim.. (ones that should be iterated over in collisions_optimized - lock (_activeprims) - { - if (!_activeprims.Contains(prim)) - _activeprims.Add(prim); - //else - // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent"); - } + if (!_activeprims.Contains(prim)) + _activeprims.Add(prim); + //else + // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent"); } public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, @@ -2150,8 +2151,7 @@ namespace OpenSim.Region.Physics.OdePlugin /// internal void DeactivatePrim(OdePrim prim) { - lock (_activeprims) - _activeprims.Remove(prim); + _activeprims.Remove(prim); } public override void RemovePrim(PhysicsActor prim) @@ -2818,13 +2818,10 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); } // Move other active objects - lock (_activeprims) + foreach (OdePrim prim in _activeprims) { - foreach (OdePrim prim in _activeprims) - { - prim.m_collisionscore = 0; - prim.Move(timeStep); - } + prim.m_collisionscore = 0; + prim.Move(timeStep); } //if ((framecount % m_randomizeWater) == 0) @@ -2893,20 +2890,16 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); defects.Clear(); } - lock (_activeprims) - { - //if (timeStep < 0.2f) - { - foreach (OdePrim prim in _activeprims) - { - if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag)) - { - prim.UpdatePositionAndVelocity(); + //if (timeStep < 0.2f) - if (SupportsNINJAJoints) - SimulateActorPendingJoints(prim); - } - } + foreach (OdePrim prim in _activeprims) + { + if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag)) + { + prim.UpdatePositionAndVelocity(); + + if (SupportsNINJAJoints) + SimulateActorPendingJoints(prim); } } From 4ddff7eb0ffbb1cc43eac2543296e241574e31be Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 21:29:56 +0000 Subject: [PATCH 20/38] Get rid of OdeCharacter != null checks since OdeScene._characters can never contain a null character. Ignoring the ancient code glyphs not to do this.... --- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 21 ++++---------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index d1c1c25e44..e6cf915361 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -1538,12 +1538,6 @@ namespace OpenSim.Region.Physics.OdePlugin { // Reset the collision values to false // since we don't know if we're colliding yet - - // For some reason this can happen. Don't ask... - // - if (chr == null) - continue; - if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero) continue; @@ -2056,7 +2050,6 @@ namespace OpenSim.Region.Physics.OdePlugin //m_log.Debug("RemoveAllJointsConnectedToActor: start"); if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null) { - List jointsToRemove = new List(); //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism) foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName]) @@ -2801,10 +2794,7 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); // Move characters foreach (OdeCharacter actor in _characters) - { - if (actor != null) - actor.Move(defects); - } + actor.Move(defects); if (defects.Count != 0) { @@ -2870,13 +2860,10 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); foreach (OdeCharacter actor in _characters) { - if (actor != null) - { - if (actor.bad) - m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); + if (actor.bad) + m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); - actor.UpdatePositionAndVelocity(defects); - } + actor.UpdatePositionAndVelocity(defects); } if (defects.Count != 0) From c4e4a29478c635bb5759fa5b815d86e39cb3a794 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 21:31:26 +0000 Subject: [PATCH 21/38] Slightly improve "Unable to space collide" logging message, though I don't think I've ever seen this. --- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index e6cf915361..e219535102 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -1556,8 +1556,9 @@ namespace OpenSim.Region.Physics.OdePlugin } catch (AccessViolationException) { - m_log.Warn("[PHYSICS]: Unable to space collide"); + m_log.WarnFormat("[PHYSICS]: Unable to space collide {0}", Name); } + //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y); //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10) //{ From b89c48b1bead12856437642b4044b2606a043f98 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 21 Nov 2011 22:06:43 +0000 Subject: [PATCH 22/38] Improve the error messages returned if the HelloNeighbour call fails. This is the message a region sends to its neighbours when it comes up --- .../Neighbour/NeighbourServiceConnector.cs | 65 +++++++++++++------ 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs b/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs index 2cae02d42a..888b072013 100644 --- a/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs +++ b/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs @@ -87,12 +87,26 @@ namespace OpenSim.Services.Connectors public bool DoHelloNeighbourCall(GridRegion region, RegionInfo thisRegion) { string uri = region.ServerURI + "region/" + thisRegion.RegionID + "/"; - //m_log.Debug(" >>> DoHelloNeighbourCall <<< " + uri); +// m_log.Debug(" >>> DoHelloNeighbourCall <<< " + uri); - WebRequest HelloNeighbourRequest = WebRequest.Create(uri); - HelloNeighbourRequest.Method = "POST"; - HelloNeighbourRequest.ContentType = "application/json"; - HelloNeighbourRequest.Timeout = 10000; + WebRequest helloNeighbourRequest; + + try + { + helloNeighbourRequest = WebRequest.Create(uri); + } + catch (Exception e) + { + m_log.WarnFormat( + "[NEIGHBOUR SERVICE CONNCTOR]: Unable to parse uri {0} to send HelloNeighbour from {1} to {2}. Exception {3}{4}", + uri, thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); + + return false; + } + + helloNeighbourRequest.Method = "POST"; + helloNeighbourRequest.ContentType = "application/json"; + helloNeighbourRequest.Timeout = 10000; // Fill it in OSDMap args = null; @@ -102,38 +116,48 @@ namespace OpenSim.Services.Connectors } catch (Exception e) { - m_log.Debug("[REST COMMS]: PackRegionInfoData failed with exception: " + e.Message); + m_log.WarnFormat( + "[NEIGHBOUR SERVICE CONNCTOR]: PackRegionInfoData failed for HelloNeighbour from {0} to {1}. Exception {2}{3}", + thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); + return false; } + // Add the regionhandle of the destination region args["destination_handle"] = OSD.FromString(region.RegionHandle.ToString()); string strBuffer = ""; byte[] buffer = new byte[1]; + try { strBuffer = OSDParser.SerializeJsonString(args); UTF8Encoding str = new UTF8Encoding(); buffer = str.GetBytes(strBuffer); - } catch (Exception e) { - m_log.WarnFormat("[REST COMMS]: Exception thrown on serialization of HelloNeighbour: {0}", e.Message); + m_log.WarnFormat( + "[NEIGHBOUR SERVICE CONNCTOR]: Exception thrown on serialization of HelloNeighbour from {0} to {1}. Exception {2}{3}", + thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); + return false; } Stream os = null; try { // send the Post - HelloNeighbourRequest.ContentLength = buffer.Length; //Count bytes to send - os = HelloNeighbourRequest.GetRequestStream(); + helloNeighbourRequest.ContentLength = buffer.Length; //Count bytes to send + os = helloNeighbourRequest.GetRequestStream(); os.Write(buffer, 0, strBuffer.Length); //Send it //m_log.InfoFormat("[REST COMMS]: Posted HelloNeighbour request to remote sim {0}", uri); } - catch (Exception ex) + catch (Exception e) { - m_log.InfoFormat("[REST COMMS]: Unable to send HelloNeighbour to {0}: {1}", region.RegionName, ex.Message); + m_log.WarnFormat( + "[NEIGHBOUR SERVICE CONNCTOR]: Unable to send HelloNeighbour from {0} to {1}. Exception {2}{3}", + thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); + return false; } finally @@ -148,10 +172,12 @@ namespace OpenSim.Services.Connectors StreamReader sr = null; try { - WebResponse webResponse = HelloNeighbourRequest.GetResponse(); + WebResponse webResponse = helloNeighbourRequest.GetResponse(); if (webResponse == null) { - m_log.Info("[REST COMMS]: Null reply on DoHelloNeighbourCall post"); + m_log.DebugFormat( + "[REST COMMS]: Null reply on DoHelloNeighbourCall post from {0} to {1}", + thisRegion.RegionName, region.RegionName); } sr = new StreamReader(webResponse.GetResponseStream()); @@ -160,9 +186,12 @@ namespace OpenSim.Services.Connectors //m_log.InfoFormat("[REST COMMS]: DoHelloNeighbourCall reply was {0} ", reply); } - catch (Exception ex) + catch (Exception e) { - m_log.InfoFormat("[REST COMMS]: exception on reply of DoHelloNeighbourCall {0}", ex.Message); + m_log.WarnFormat( + "[NEIGHBOUR SERVICE CONNCTOR]: Exception on reply of DoHelloNeighbourCall from {0} back to {1}. Exception {2}{3}", + region.RegionName, thisRegion.RegionName, e.Message, e.StackTrace); + return false; } finally @@ -172,8 +201,6 @@ namespace OpenSim.Services.Connectors } return true; - } - } -} +} \ No newline at end of file From daf99f8c0ac874971c829b18a2372be1c4ee9541 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Nov 2011 21:51:00 +0000 Subject: [PATCH 23/38] slightly simplify OdeScene.Simulate() by removing bool processtaints, since we can inspect count of taint lists instead. also groups OdeCharacter.CreateOdeStructures() and DestroyOdeStructures() together --- .../Region/Physics/OdePlugin/ODECharacter.cs | 234 +++++++++--------- OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 1 - OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 34 +-- 3 files changed, 128 insertions(+), 141 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index cfe64f2781..489a23a273 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -541,123 +541,6 @@ namespace OpenSim.Region.Physics.OdePlugin d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop } - /// - /// This creates the Avatar's physical Surrogate in ODE at the position supplied - /// - /// - /// WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access - /// to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only - /// place that is safe to call this routine AvatarGeomAndBodyCreation. - /// - /// - /// - /// - /// - private void CreateOdeStructures(float npositionX, float npositionY, float npositionZ, float tensor) - { - int dAMotorEuler = 1; -// _parent_scene.waitForSpaceUnlock(_parent_scene.space); - if (CAPSULE_LENGTH <= 0) - { - m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); - CAPSULE_LENGTH = 0.01f; - } - - if (CAPSULE_RADIUS <= 0) - { - m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); - CAPSULE_RADIUS = 0.01f; - } - - Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH); - - d.GeomSetCategoryBits(Shell, (int)m_collisionCategories); - d.GeomSetCollideBits(Shell, (int)m_collisionFlags); - - d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH); - Body = d.BodyCreate(_parent_scene.world); - d.BodySetPosition(Body, npositionX, npositionY, npositionZ); - - _position.X = npositionX; - _position.Y = npositionY; - _position.Z = npositionZ; - - m_taintPosition = _position; - - d.BodySetMass(Body, ref ShellMass); - d.Matrix3 m_caprot; - // 90 Stand up on the cap of the capped cyllinder - if (_parent_scene.IsAvCapsuleTilted) - { - d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2)); - } - else - { - d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2)); - } - - d.GeomSetRotation(Shell, ref m_caprot); - d.BodySetRotation(Body, ref m_caprot); - - d.GeomSetBody(Shell, Body); - - // The purpose of the AMotor here is to keep the avatar's physical - // surrogate from rotating while moving - Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); - d.JointAttach(Amotor, Body, IntPtr.Zero); - d.JointSetAMotorMode(Amotor, dAMotorEuler); - d.JointSetAMotorNumAxes(Amotor, 3); - d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0); - d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0); - d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1); - d.JointSetAMotorAngle(Amotor, 0, 0); - d.JointSetAMotorAngle(Amotor, 1, 0); - d.JointSetAMotorAngle(Amotor, 2, 0); - - // These lowstops and high stops are effectively (no wiggle room) - if (_parent_scene.IsAvCapsuleTilted) - { - d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f); - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f); - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f); - } - else - { - #region Documentation of capsule motor LowStop and HighStop parameters - // Intentionally introduce some tilt into the capsule by setting - // the motor stops to small epsilon values. This small tilt prevents - // the capsule from falling into the terrain; a straight-up capsule - // (with -0..0 motor stops) falls into the terrain for reasons yet - // to be comprehended in their entirety. - #endregion - AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero); - d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f); - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f); - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop - } - - // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the - // capped cyllinder will fall over - d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f); - d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor); - - //d.Matrix3 bodyrotation = d.BodyGetRotation(Body); - //d.QfromR( - //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068, - // - //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22); - //standupStraight(); - - _parent_scene.geom_name_map[Shell] = Name; - _parent_scene.actor_name_map[Shell] = this; - } - /// /// Uses the capped cyllinder volume formula to calculate the avatar's mass. /// This may be used in calculations in the scene/scenepresence @@ -1125,6 +1008,123 @@ namespace OpenSim.Region.Physics.OdePlugin } } + /// + /// This creates the Avatar's physical Surrogate in ODE at the position supplied + /// + /// + /// WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access + /// to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only + /// place that is safe to call this routine AvatarGeomAndBodyCreation. + /// + /// + /// + /// + /// + private void CreateOdeStructures(float npositionX, float npositionY, float npositionZ, float tensor) + { + int dAMotorEuler = 1; +// _parent_scene.waitForSpaceUnlock(_parent_scene.space); + if (CAPSULE_LENGTH <= 0) + { + m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); + CAPSULE_LENGTH = 0.01f; + } + + if (CAPSULE_RADIUS <= 0) + { + m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); + CAPSULE_RADIUS = 0.01f; + } + + Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH); + + d.GeomSetCategoryBits(Shell, (int)m_collisionCategories); + d.GeomSetCollideBits(Shell, (int)m_collisionFlags); + + d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH); + Body = d.BodyCreate(_parent_scene.world); + d.BodySetPosition(Body, npositionX, npositionY, npositionZ); + + _position.X = npositionX; + _position.Y = npositionY; + _position.Z = npositionZ; + + m_taintPosition = _position; + + d.BodySetMass(Body, ref ShellMass); + d.Matrix3 m_caprot; + // 90 Stand up on the cap of the capped cyllinder + if (_parent_scene.IsAvCapsuleTilted) + { + d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2)); + } + else + { + d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2)); + } + + d.GeomSetRotation(Shell, ref m_caprot); + d.BodySetRotation(Body, ref m_caprot); + + d.GeomSetBody(Shell, Body); + + // The purpose of the AMotor here is to keep the avatar's physical + // surrogate from rotating while moving + Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); + d.JointAttach(Amotor, Body, IntPtr.Zero); + d.JointSetAMotorMode(Amotor, dAMotorEuler); + d.JointSetAMotorNumAxes(Amotor, 3); + d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0); + d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0); + d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1); + d.JointSetAMotorAngle(Amotor, 0, 0); + d.JointSetAMotorAngle(Amotor, 1, 0); + d.JointSetAMotorAngle(Amotor, 2, 0); + + // These lowstops and high stops are effectively (no wiggle room) + if (_parent_scene.IsAvCapsuleTilted) + { + d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f); + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f); + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f); + } + else + { + #region Documentation of capsule motor LowStop and HighStop parameters + // Intentionally introduce some tilt into the capsule by setting + // the motor stops to small epsilon values. This small tilt prevents + // the capsule from falling into the terrain; a straight-up capsule + // (with -0..0 motor stops) falls into the terrain for reasons yet + // to be comprehended in their entirety. + #endregion + AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero); + d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f); + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f); + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop + } + + // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the + // capped cyllinder will fall over + d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f); + d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor); + + //d.Matrix3 bodyrotation = d.BodyGetRotation(Body); + //d.QfromR( + //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068, + // + //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22); + //standupStraight(); + + _parent_scene.geom_name_map[Shell] = Name; + _parent_scene.actor_name_map[Shell] = this; + } + /// /// Cleanup the things we use in the scene. /// diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index fec46939f5..94e6185e3b 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -272,7 +272,6 @@ namespace OpenSim.Region.Physics.OdePlugin m_taintadd = true; _parent_scene.AddPhysicsActorTaint(this); - // don't do .add() here; old geoms get recycled with the same hash } public override int PhysicsActorType diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index e219535102..72e9ca0f95 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -2160,7 +2160,6 @@ namespace OpenSim.Region.Physics.OdePlugin p.setPrimForRemoval(); AddPhysicsActorTaint(prim); - //RemovePrimThreadLocked(p); } } } @@ -2607,15 +2606,17 @@ namespace OpenSim.Region.Physics.OdePlugin /// /// Called after our prim properties are set Scale, position etc. + /// + /// /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex /// This assures us that we have no race conditions - /// - /// - public override void AddPhysicsActorTaint(PhysicsActor prim) + /// + /// + public override void AddPhysicsActorTaint(PhysicsActor actor) { - if (prim is OdePrim) + if (actor is OdePrim) { - OdePrim taintedprim = ((OdePrim) prim); + OdePrim taintedprim = ((OdePrim)actor); lock (_taintedPrimLock) { if (!(_taintedPrimH.Contains(taintedprim))) @@ -2627,11 +2628,10 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); _taintedPrimL.Add(taintedprim); // List for ordered readout } } - return; } - else if (prim is OdeCharacter) + else if (actor is OdeCharacter) { - OdeCharacter taintedchar = ((OdeCharacter)prim); + OdeCharacter taintedchar = ((OdeCharacter)actor); lock (_taintedActors) { if (!(_taintedActors.Contains(taintedchar))) @@ -2734,29 +2734,18 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); { try { - // Insert, remove Characters - bool processedtaints = false; - lock (_taintedActors) { if (_taintedActors.Count > 0) { foreach (OdeCharacter character in _taintedActors) - { character.ProcessTaints(); - processedtaints = true; - //character.m_collisionscore = 0; - } - - if (processedtaints) + if (_taintedActors.Count > 0) _taintedActors.Clear(); } } - // Modify other objects in the scene. - processedtaints = false; - lock (_taintedPrimLock) { foreach (OdePrim prim in _taintedPrimL) @@ -2772,7 +2761,6 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); prim.ProcessTaints(); } - processedtaints = true; prim.m_collisionscore = 0; // This loop can block up the Heartbeat for a very long time on large regions. @@ -2785,7 +2773,7 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); if (SupportsNINJAJoints) SimulatePendingNINJAJoints(); - if (processedtaints) + if (_taintedPrimL.Count > 0) { //Console.WriteLine("Simulate calls Clear of _taintedPrim list"); _taintedPrimH.Clear(); From b0fe0464af9a11dda184d3613eca734cd8c9f21e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Nov 2011 22:13:57 +0000 Subject: [PATCH 24/38] Stop an exception being thrown and a teleport/border cross failing if the desintation sim has no active script engines. This involves getting IScene.RequestModuleInterfaces() to return an empty array (as was stated in the method doc) rather than an array containing one null entry. Callers adjusted to stop checking for the list reference being null (which never happened anyway) --- OpenSim/Framework/IScene.cs | 22 +++++++++++-- .../Framework/Scenes/Scene.Inventory.cs | 13 ++------ OpenSim/Region/Framework/Scenes/SceneBase.cs | 2 +- .../Scenes/SceneObjectPartInventory.cs | 10 +++--- .../Region/Framework/Scenes/ScenePresence.cs | 32 +++++++++---------- 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs index f1b4732bf0..76b731f0f3 100644 --- a/OpenSim/Framework/IScene.cs +++ b/OpenSim/Framework/IScene.cs @@ -102,12 +102,28 @@ namespace OpenSim.Framework bool TryGetScenePresence(UUID agentID, out object scenePresence); - T RequestModuleInterface(); - T[] RequestModuleInterfaces(); - + /// + /// Register an interface to a region module. This allows module methods to be called directly as + /// well as via events. If there is already a module registered for this interface, it is not replaced + /// (is this the best behaviour?) + /// + /// void RegisterModuleInterface(M mod); + void StackModuleInterface(M mod); + /// + /// For the given interface, retrieve the region module which implements it. + /// + /// null if there is no registered module implementing that interface + T RequestModuleInterface(); + + /// + /// For the given interface, retrieve an array of region modules that implement it. + /// + /// an empty array if there are no registered modules implementing that interface + T[] RequestModuleInterfaces(); + // void AddCommand(object module, string command, string shorthelp, string longhelp, CommandDelegate callback); ISceneObject DeserializeObject(string representation); diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 663aa22efb..26eb7290ac 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -82,16 +82,9 @@ namespace OpenSim.Region.Framework.Scenes m_log.Info("[PRIM INVENTORY]: Starting scripts in scene"); IScriptModule[] engines = RequestModuleInterfaces(); - if (engines != null) - { - foreach (IScriptModule engine in engines) - { - if (engine != null) - { - engine.StartProcessing(); - } - } - } + + foreach (IScriptModule engine in engines) + engine.StartProcessing(); } public void AddUploadedInventoryItem(UUID agentID, InventoryItemBase item) diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs index dee2ecb291..0336fe5a42 100644 --- a/OpenSim/Region/Framework/Scenes/SceneBase.cs +++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs @@ -449,7 +449,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - return new T[] { default(T) }; + return new T[] {}; } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 94467414eb..d80944b554 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -232,8 +232,6 @@ namespace OpenSim.Region.Framework.Scenes ArrayList ret = new ArrayList(); IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces(); - if (engines == null) // No engine at all - return ret; foreach (IScriptModule e in engines) { @@ -329,7 +327,7 @@ namespace OpenSim.Region.Framework.Scenes private void RestoreSavedScriptState(UUID oldID, UUID newID) { IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces(); - if (engines == null) // No engine at all + if (engines.Length == 0) // No engine at all return; if (m_part.ParentGroup.m_savedScriptState.ContainsKey(oldID)) @@ -369,6 +367,7 @@ namespace OpenSim.Region.Framework.Scenes m_part.ParentGroup.m_savedScriptState[oldID] = newDoc.OuterXml; } + foreach (IScriptModule e in engines) { if (e != null) @@ -377,6 +376,7 @@ namespace OpenSim.Region.Framework.Scenes break; } } + m_part.ParentGroup.m_savedScriptState.Remove(oldID); } } @@ -1129,7 +1129,7 @@ namespace OpenSim.Region.Framework.Scenes IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces(); - if (engines == null) // No engine at all + if (engines.Length == 0) // No engine at all return ret; List scripts = GetInventoryScripts(); @@ -1157,7 +1157,7 @@ namespace OpenSim.Region.Framework.Scenes public void ResumeScripts() { IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces(); - if (engines == null) + if (engines.Length == 0) return; List scripts = GetInventoryScripts(); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 7d901c9b10..c2d3501825 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3525,23 +3525,23 @@ namespace OpenSim.Region.Framework.Scenes /// The arguments for the event public void SendScriptEventToAttachments(string eventName, Object[] args) { - if (m_scriptEngines != null) - { - lock (m_attachments) - { - foreach (SceneObjectGroup grp in m_attachments) - { - // 16384 is CHANGED_ANIMATION - // - // Send this to all attachment root prims - // - foreach (IScriptModule m in m_scriptEngines) - { - if (m == null) // No script engine loaded - continue; + if (m_scriptEngines.Length == 0) + return; - m.PostObjectEvent(grp.RootPart.UUID, "changed", new Object[] { (int)Changed.ANIMATION }); - } + lock (m_attachments) + { + foreach (SceneObjectGroup grp in m_attachments) + { + // 16384 is CHANGED_ANIMATION + // + // Send this to all attachment root prims + // + foreach (IScriptModule m in m_scriptEngines) + { + if (m == null) // No script engine loaded + continue; + + m.PostObjectEvent(grp.RootPart.UUID, "changed", new Object[] { (int)Changed.ANIMATION }); } } } From d639f7fdf3ddb4bbb825a08c5c153b5e93b27231 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Nov 2011 22:16:09 +0000 Subject: [PATCH 25/38] minor: remove mono compiler warning --- .../OptionalModules/PhysicsParameters/PhysicsParameters.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs index 2a44360f28..23ef7576f3 100755 --- a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs +++ b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs @@ -48,7 +48,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters public class PhysicsParameters : ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static string LogHeader = "[PHYSICS PARAMETERS]"; +// private static string LogHeader = "[PHYSICS PARAMETERS]"; private List m_scenes = new List(); private static bool m_commandsLoaded = false; From fcb066cb5f8d56f13cfbdd4cef9f51a854b95854 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Nov 2011 22:23:52 +0000 Subject: [PATCH 26/38] Comment out unimplemented and uncalled RegionCombinerModule.UnCombineRegion() --- .../RegionCombinerModule.cs | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs index 92cbbc68f1..3f9834c5ab 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs @@ -841,33 +841,33 @@ namespace OpenSim.Region.RegionCombinerModule { } - /// - /// TODO: - /// - /// - public void UnCombineRegion(RegionData rdata) - { - lock (m_regions) - { - if (m_regions.ContainsKey(rdata.RegionId)) - { - // uncombine root region and virtual regions - } - else - { - foreach (RegionConnections r in m_regions.Values) - { - foreach (RegionData rd in r.ConnectedRegions) - { - if (rd.RegionId == rdata.RegionId) - { - // uncombine virtual region - } - } - } - } - } - } +// /// +// /// TODO: +// /// +// /// +// public void UnCombineRegion(RegionData rdata) +// { +// lock (m_regions) +// { +// if (m_regions.ContainsKey(rdata.RegionId)) +// { +// // uncombine root region and virtual regions +// } +// else +// { +// foreach (RegionConnections r in m_regions.Values) +// { +// foreach (RegionData rd in r.ConnectedRegions) +// { +// if (rd.RegionId == rdata.RegionId) +// { +// // uncombine virtual region +// } +// } +// } +// } +// } +// } // Create a set of infinite borders around the whole aabb of the combined island. private void AdjustLargeRegionBounds() From af90b527314d6cf441dcd593886739ac77b68558 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Nov 2011 22:28:46 +0000 Subject: [PATCH 27/38] Comment out uncalled OdeScene.UnCombine() --- .../Region/Physics/Manager/PhysicsScene.cs | 10 +- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 116 +++++++++--------- 2 files changed, 60 insertions(+), 66 deletions(-) diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index eaa1175fce..7ab295aec0 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs @@ -221,15 +221,9 @@ namespace OpenSim.Region.Physics.Manager return false; } - public virtual void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) - { - return; - } + public virtual void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) {} - public virtual void UnCombine(PhysicsScene pScene) - { - - } + public virtual void UnCombine(PhysicsScene pScene) {} /// /// Queue a raycast against the physics scene. diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 72e9ca0f95..b5436bd664 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -3583,64 +3583,64 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); return true; } - public override void UnCombine(PhysicsScene pScene) - { - IntPtr localGround = IntPtr.Zero; -// float[] localHeightfield; - bool proceed = false; - List geomDestroyList = new List(); - - lock (OdeLock) - { - if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround)) - { - foreach (IntPtr geom in TerrainHeightFieldHeights.Keys) - { - if (geom == localGround) - { -// localHeightfield = TerrainHeightFieldHeights[geom]; - proceed = true; - } - else - { - geomDestroyList.Add(geom); - } - } - - if (proceed) - { - m_worldOffset = Vector3.Zero; - WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); - m_parentScene = null; - - foreach (IntPtr g in geomDestroyList) - { - // removingHeightField needs to be done or the garbage collector will - // collect the terrain data before we tell ODE to destroy it causing - // memory corruption - if (TerrainHeightFieldHeights.ContainsKey(g)) - { -// float[] removingHeightField = TerrainHeightFieldHeights[g]; - TerrainHeightFieldHeights.Remove(g); - - if (RegionTerrain.ContainsKey(g)) - { - RegionTerrain.Remove(g); - } - - d.GeomDestroy(g); - //removingHeightField = new float[0]; - } - } - - } - else - { - m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data."); - } - } - } - } +// public override void UnCombine(PhysicsScene pScene) +// { +// IntPtr localGround = IntPtr.Zero; +//// float[] localHeightfield; +// bool proceed = false; +// List geomDestroyList = new List(); +// +// lock (OdeLock) +// { +// if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround)) +// { +// foreach (IntPtr geom in TerrainHeightFieldHeights.Keys) +// { +// if (geom == localGround) +// { +//// localHeightfield = TerrainHeightFieldHeights[geom]; +// proceed = true; +// } +// else +// { +// geomDestroyList.Add(geom); +// } +// } +// +// if (proceed) +// { +// m_worldOffset = Vector3.Zero; +// WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); +// m_parentScene = null; +// +// foreach (IntPtr g in geomDestroyList) +// { +// // removingHeightField needs to be done or the garbage collector will +// // collect the terrain data before we tell ODE to destroy it causing +// // memory corruption +// if (TerrainHeightFieldHeights.ContainsKey(g)) +// { +//// float[] removingHeightField = TerrainHeightFieldHeights[g]; +// TerrainHeightFieldHeights.Remove(g); +// +// if (RegionTerrain.ContainsKey(g)) +// { +// RegionTerrain.Remove(g); +// } +// +// d.GeomDestroy(g); +// //removingHeightField = new float[0]; +// } +// } +// +// } +// else +// { +// m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data."); +// } +// } +// } +// } public override void SetWaterLevel(float baseheight) { From ace4324e753435e317ec388b5b25a8e3ffd84db4 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Nov 2011 22:37:06 +0000 Subject: [PATCH 28/38] Stop removing actor from the hash maps in OdeScene.RemoveCharacter() since this is now being down in OdeCharacter.DestroyOdeStructures() --- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index b5436bd664..7b04bcf7ea 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -1735,12 +1735,7 @@ namespace OpenSim.Region.Physics.OdePlugin internal void RemoveCharacter(OdeCharacter chr) { - if (_characters.Contains(chr)) - { - _characters.Remove(chr); - geom_name_map.Remove(chr.Shell); - actor_name_map.Remove(chr.Shell); - } + _characters.Remove(chr); } private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, From b56410285b1af7c5fc2b4a84d8c9c734d2238ff0 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 22 Nov 2011 22:46:25 +0000 Subject: [PATCH 29/38] Log error if we attempt to add/remove an OdeCharacter from the _characters list inappropriately --- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 56 ++++++++++++-------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 7b04bcf7ea..0456f5667c 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -377,8 +377,7 @@ namespace OpenSim.Region.Physics.OdePlugin /// Name of the scene. Useful in debug messages. public OdeScene(string name) { - m_log - = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name); + m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name); Name = name; @@ -769,7 +768,7 @@ namespace OpenSim.Region.Physics.OdePlugin } catch (AccessViolationException) { - m_log.Warn("[PHYSICS]: Unable to collide test a space"); + m_log.Warn("[ODE SCENE]: Unable to collide test a space"); return; } //Colliding a space or a geom with a space or a geom. so drill down @@ -821,17 +820,17 @@ namespace OpenSim.Region.Physics.OdePlugin count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf); if (count > contacts.Length) - m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); + m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); } catch (SEHException) { 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."); + "[ODE SCENE]: 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."); base.TriggerPhysicsBasedRestart(); } catch (Exception e) { - m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message); + m_log.WarnFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message); return; } @@ -1556,7 +1555,7 @@ namespace OpenSim.Region.Physics.OdePlugin } catch (AccessViolationException) { - m_log.WarnFormat("[PHYSICS]: Unable to space collide {0}", Name); + m_log.WarnFormat("[ODE SCENE]: Unable to space collide {0}", Name); } //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y); @@ -1587,13 +1586,13 @@ namespace OpenSim.Region.Physics.OdePlugin removeprims = new List(); } removeprims.Add(chr); - m_log.Debug("[PHYSICS]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!"); + m_log.Debug("[ODE SCENE]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!"); } } } catch (AccessViolationException) { - m_log.Warn("[PHYSICS]: Unable to space collide"); + m_log.Warn("[ODE SCENE]: Unable to space collide"); } } } @@ -1729,13 +1728,24 @@ namespace OpenSim.Region.Physics.OdePlugin _characters.Add(chr); if (chr.bad) - m_log.ErrorFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid); + m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to characters list", chr.m_uuid); + } + else + { + m_log.ErrorFormat( + "[ODE SCENE]: Tried to add character {0} {1} but they are already in the set!", + chr.Name, chr.LocalID); } } internal void RemoveCharacter(OdeCharacter chr) { - _characters.Remove(chr); + if (_characters.Contains(chr)) + _characters.Remove(chr); + else + m_log.ErrorFormat( + "[ODE SCENE]: Tried to remove character {0} {1} but they are not in the list!", + chr.Name, chr.LocalID); } private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, @@ -2222,7 +2232,7 @@ namespace OpenSim.Region.Physics.OdePlugin //m_log.Warn(prim.prim_geom); if (!prim.RemoveGeom()) - m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene"); + m_log.Warn("[ODE SCENE]: Unable to remove prim from physics scene"); lock (_prims) _prims.Remove(prim); @@ -2314,7 +2324,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace + + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace + " Geom:" + geom); } } @@ -2330,7 +2340,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + sGeomIsIn + " Geom:" + geom); } } @@ -2353,7 +2363,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace + " Geom:" + geom); } } @@ -2373,7 +2383,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace + " Geom:" + geom); } } @@ -2389,7 +2399,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + sGeomIsIn + " Geom:" + geom); } } @@ -2633,7 +2643,7 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); { _taintedActors.Add(taintedchar); if (taintedchar.bad) - m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid); + m_log.DebugFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid); } } } @@ -2836,7 +2846,7 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); } catch (Exception e) { - m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e); + m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e); } timeLeft -= ODE_STEPSIZE; @@ -2845,7 +2855,7 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); foreach (OdeCharacter actor in _characters) { if (actor.bad) - m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); + m_log.WarnFormat("[ODE SCENE]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); actor.UpdatePositionAndVelocity(defects); } @@ -3405,7 +3415,7 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); { if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x])) { - m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0"); + m_log.Warn("[ODE SCENE]: Non finite heightfield element detected. Setting it to 0"); resultarr2[y, x] = 0; } returnarr[i] = resultarr2[y, x]; @@ -3436,7 +3446,7 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); private void SetTerrain(float[] heightMap, Vector3 pOffset) { int startTime = Util.EnvironmentTickCount(); - m_log.DebugFormat("[PHYSICS]: Setting terrain for {0}", Name); + m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0}", Name); // this._heightmap[i] = (double)heightMap[i]; // dbm (danx0r) -- creating a buffer zone of one extra sample all around @@ -3561,7 +3571,7 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); } m_log.DebugFormat( - "[PHYSICS]: Setting terrain for {0} took {1}ms", Name, Util.EnvironmentTickCountSubtract(startTime)); + "[ODE SCENE]: Setting terrain for {0} took {1}ms", Name, Util.EnvironmentTickCountSubtract(startTime)); } public override void DeleteTerrain() From d4e3a7fe81a155be841bc0d182aa7a14083ffa3e Mon Sep 17 00:00:00 2001 From: BlueWall Date: Sat, 19 Nov 2011 11:01:51 -0500 Subject: [PATCH 30/38] Shell Environment Variables in config Adding updated Nini and support to use shell environment variables in OpenSimulator configuration. Nini @ https://github.com/BlueWall/Nini-Dev --- .../Region/Application/ConfigurationLoader.cs | 20 +++++++++++++++++- OpenSim/Region/Application/OpenSimBase.cs | 9 +++++++- OpenSim/Tests/ConfigurationLoaderTest.cs | 4 +++- bin/Nini.dll | Bin 61440 -> 55808 bytes 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs index d0f6ab7c94..4a7c8b083b 100644 --- a/OpenSim/Region/Application/ConfigurationLoader.cs +++ b/OpenSim/Region/Application/ConfigurationLoader.cs @@ -70,7 +70,7 @@ namespace OpenSim /// /// A configuration that gets passed to modules public OpenSimConfigSource LoadConfigSettings( - IConfigSource argvSource, out ConfigSettings configSettings, + IConfigSource argvSource, EnvConfigSource envConfigSource, out ConfigSettings configSettings, out NetworkServersInfo networkInfo) { m_configSettings = configSettings = new ConfigSettings(); @@ -195,6 +195,24 @@ namespace OpenSim // Make sure command line options take precedence m_config.Source.Merge(argvSource); + + IConfig enVars = m_config.Source.Configs["Environment"]; + + if( enVars != null ) + { + string[] env_keys = enVars.GetKeys(); + + foreach ( string key in env_keys ) + { + envConfigSource.AddEnv(key, string.Empty); + } + + envConfigSource.LoadEnv(); + m_config.Source.Merge(envConfigSource); + m_config.Source.ExpandKeyValues(); + } + + ReadConfigSettings(); return m_config; diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 553786b1f7..0a78df27ce 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -108,6 +108,13 @@ namespace OpenSim get { return m_clientServers; } } + protected EnvConfigSource m_EnvConfigSource = new EnvConfigSource(); + + public EnvConfigSource envConfigSource + { + get { return m_EnvConfigSource; } + } + protected List m_clientServers = new List(); public uint HttpServerPort @@ -142,7 +149,7 @@ namespace OpenSim protected virtual void LoadConfigSettings(IConfigSource configSource) { m_configLoader = new ConfigurationLoader(); - m_config = m_configLoader.LoadConfigSettings(configSource, out m_configSettings, out m_networkServersInfo); + m_config = m_configLoader.LoadConfigSettings(configSource, envConfigSource, out m_configSettings, out m_networkServersInfo); ReadExtraConfigSettings(); } diff --git a/OpenSim/Tests/ConfigurationLoaderTest.cs b/OpenSim/Tests/ConfigurationLoaderTest.cs index c777acc0f1..067264d027 100644 --- a/OpenSim/Tests/ConfigurationLoaderTest.cs +++ b/OpenSim/Tests/ConfigurationLoaderTest.cs @@ -109,11 +109,13 @@ namespace OpenSim.Tests // Prepare call to ConfigurationLoader.LoadConfigSettings() ConfigurationLoader cl = new ConfigurationLoader(); IConfigSource argvSource = new IniConfigSource(); + EnvConfigSource envConfigSource = new EnvConfigSource(); argvSource.AddConfig("Startup").Set("inifile", mainIniFile); ConfigSettings configSettings; NetworkServersInfo networkInfo; - OpenSimConfigSource source = cl.LoadConfigSettings(argvSource, out configSettings, out networkInfo); + OpenSimConfigSource source = cl.LoadConfigSettings(argvSource, envConfigSource, + out configSettings, out networkInfo); // Remove default config config = source.Source.Configs["Startup"]; diff --git a/bin/Nini.dll b/bin/Nini.dll index 745057c3f64795a9d2709faafd6a0a942ca717f1..c421005ba38fbf969bd4dbeaaa2f1886438a7c03 100755 GIT binary patch literal 55808 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 E1)?t;O8@`> From e394f83df0d4af9f7efb826dbb49fe0eabedabdc Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 23 Nov 2011 18:00:41 +0000 Subject: [PATCH 31/38] Change random number generator property name in pCampbot --- OpenSim/Tools/pCampBot/BotManager.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index f5dd5e0847..056f991708 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -50,7 +50,12 @@ namespace pCampBot protected CommandConsole m_console; protected List m_lBot; - protected Random somthing = new Random(Environment.TickCount); + + /// + /// Random number generator. + /// + public Random Rng { get; private set; } + public IConfig Config { get; private set; } /// @@ -63,6 +68,7 @@ namespace pCampBot /// public BotManager() { + Rng = new Random(Environment.TickCount); AssetsReceived = new Dictionary(); m_console = CreateConsole(); From e9f2a9bddbb47ac8c80aeccea0022ad534cbd552 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 23 Nov 2011 21:19:10 +0000 Subject: [PATCH 32/38] get pCampBot to extract nearby and store nearby region information --- OpenSim/Tools/pCampBot/Bot.cs | 12 +++++++ OpenSim/Tools/pCampBot/BotManager.cs | 54 +++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index 7f941a497f..7c16bf4e97 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -218,7 +218,19 @@ namespace pCampBot { MakeDefaultAppearance(wear); } + Client.Self.Jump(true); + + // Extract nearby region information. + Client.Grid.GridRegion += BotManager.Grid_GridRegion; + uint xUint, yUint; + Utils.LongToUInts(Client.Network.CurrentSim.Handle, out xUint, out yUint); + ushort minX, minY, maxX, maxY; + minX = (ushort)Math.Min(0, xUint - 5); + minY = (ushort)Math.Min(0, yUint - 5); + maxX = (ushort)(xUint + 5); + maxY = (ushort)(yUint + 5); + Client.Grid.RequestMapBlocks(GridLayerType.Terrain, minX, minY, maxX, maxY, false); } else { diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 056f991708..f372f9ba0d 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -55,7 +55,7 @@ namespace pCampBot /// Random number generator. /// public Random Rng { get; private set; } - + public IConfig Config { get; private set; } /// @@ -63,6 +63,11 @@ namespace pCampBot /// public Dictionary AssetsReceived { get; private set; } + /// + /// The regions that we know about. + /// + public Dictionary RegionsKnown { get; private set; } + /// /// Constructor Creates MainConsole.Instance to take commands and provide the place to write data /// @@ -70,6 +75,7 @@ namespace pCampBot { Rng = new Random(Environment.TickCount); AssetsReceived = new Dictionary(); + RegionsKnown = new Dictionary(); m_console = CreateConsole(); MainConsole.Instance = m_console; @@ -99,6 +105,11 @@ namespace pCampBot "Shutdown bots and exit", HandleShutdown); + m_console.Commands.AddCommand("bot", false, "show regions", + "show regions", + "Show regions known to bots", + HandleShowRegions); + m_console.Commands.AddCommand("bot", false, "show status", "show status", "Shows the status of all bots", @@ -246,17 +257,33 @@ namespace pCampBot }); } + private void HandleShowRegions(string module, string[] cmd) + { + string outputFormat = "{0,-30} {1, -20} {2, -5} {3, -5}"; + MainConsole.Instance.OutputFormat(outputFormat, "Name", "Handle", "X", "Y"); + + lock (RegionsKnown) + { + foreach (GridRegion region in RegionsKnown.Values) + { + MainConsole.Instance.OutputFormat( + outputFormat, region.Name, region.RegionHandle, region.X, region.Y); + } + } + } + private void HandleShowStatus(string module, string[] cmd) { - string outputFormat = "{0,-30} {1,-14}"; - MainConsole.Instance.OutputFormat(outputFormat, "Name", "Status"); + string outputFormat = "{0,-30} {1, -30} {2,-14}"; + MainConsole.Instance.OutputFormat(outputFormat, "Name", "Region", "Status"); lock (m_lBot) { foreach (Bot pb in m_lBot) { MainConsole.Instance.OutputFormat( - outputFormat, pb.Name, (pb.IsConnected ? "Connected" : "Disconnected")); + outputFormat, + pb.Name, pb.Client.Network.CurrentSim.Name, pb.IsConnected ? "Connected" : "Disconnected"); } } } @@ -280,5 +307,24 @@ namespace pCampBot // if (newbots > 0) // addbots(newbots); // } + + internal void Grid_GridRegion(object o, GridRegionEventArgs args) + { + lock (RegionsKnown) + { + GridRegion newRegion = args.Region; + + if (RegionsKnown.ContainsKey(newRegion.RegionHandle)) + { + return; + } + else + { + m_log.DebugFormat( + "[BOT MANAGER]: Adding {0} {1} to known regions", newRegion.Name, newRegion.RegionHandle); + RegionsKnown[newRegion.RegionHandle] = newRegion; + } + } + } } } From 9ae0641871418813ad4e9dd4591396e0b023140b Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 23 Nov 2011 21:33:10 +0000 Subject: [PATCH 33/38] Rename Bot.BotManager to Manager --- OpenSim/Tools/pCampBot/Bot.cs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index 7c16bf4e97..7a73e3f13a 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -49,8 +49,15 @@ namespace pCampBot public delegate void AnEvent(Bot callbot, EventType someevent); // event delegate for bot events - public BotManager BotManager { get; private set; } - private IConfig startupConfig; // bot config, passed from BotManager + /// + /// Bot manager. + /// + public BotManager Manager { get; private set; } + + /// + /// Bot config, passed from BotManager. + /// + private IConfig startupConfig; /// /// Behaviours implemented by this bot. @@ -132,7 +139,7 @@ namespace pCampBot Password = password; LoginUri = loginUri; - BotManager = bm; + Manager = bm; startupConfig = bm.Config; readconfig(); @@ -222,7 +229,7 @@ namespace pCampBot Client.Self.Jump(true); // Extract nearby region information. - Client.Grid.GridRegion += BotManager.Grid_GridRegion; + Client.Grid.GridRegion += Manager.Grid_GridRegion; uint xUint, yUint; Utils.LongToUInts(Client.Network.CurrentSim.Handle, out xUint, out yUint); ushort minX, minY, maxX, maxY; @@ -484,13 +491,13 @@ namespace pCampBot private void GetTexture(UUID textureID) { - lock (BotManager.AssetsReceived) + lock (Manager.AssetsReceived) { // Don't request assets more than once. - if (BotManager.AssetsReceived.ContainsKey(textureID)) + if (Manager.AssetsReceived.ContainsKey(textureID)) return; - BotManager.AssetsReceived[textureID] = false; + Manager.AssetsReceived[textureID] = false; Client.Assets.RequestImage(textureID, ImageType.Normal, Asset_TextureCallback_Texture); } } @@ -502,8 +509,8 @@ namespace pCampBot public void Asset_ReceivedCallback(AssetDownload transfer, Asset asset) { - lock (BotManager.AssetsReceived) - BotManager.AssetsReceived[asset.AssetID] = true; + lock (Manager.AssetsReceived) + Manager.AssetsReceived[asset.AssetID] = true; // if (wear == "save") // { From 1126efdcd062c46e7e6212c86b692d11e570d8b3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 23 Nov 2011 21:33:54 +0000 Subject: [PATCH 34/38] In pCampbot, change "show status" command to "show bots" --- OpenSim/Tools/pCampBot/BotManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index f372f9ba0d..836d3f75f3 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -110,8 +110,8 @@ namespace pCampBot "Show regions known to bots", HandleShowRegions); - m_console.Commands.AddCommand("bot", false, "show status", - "show status", + m_console.Commands.AddCommand("bot", false, "show bots", + "show bots", "Shows the status of all bots", HandleShowStatus); From d145750e878c75e7d7a78eb9ef8dddaab81cc159 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 23 Nov 2011 22:05:11 +0000 Subject: [PATCH 35/38] Add teleport behaviour to pCampBot This teleports the bot to any other regions +/- 5 on the x or y axis. Quite aggressive at the moment since teleports keep occuring at a 1-10secs random interval. No checking yet to see if teleport was successful. --- .../pCampBot/Behaviours/TeleportBehaviour.cs | 73 +++++++++++++++++++ OpenSim/Tools/pCampBot/BotManager.cs | 3 + OpenSim/Tools/pCampBot/pCampBot.cs | 2 +- 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs diff --git a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs new file mode 100644 index 0000000000..4624494ea6 --- /dev/null +++ b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs @@ -0,0 +1,73 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using log4net; +using OpenMetaverse; +using pCampBot.Interfaces; + +namespace pCampBot +{ + /// + /// Teleport to a random region on the grid. + /// + public class TeleportBehaviour : IBehaviour + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public void Action(Bot bot) + { + Random rng = bot.Manager.Rng; + GridRegion[] knownRegions; + + lock (bot.Manager.RegionsKnown) + { + if (bot.Manager.RegionsKnown.Count == 0) + { + m_log.DebugFormat( + "[TELEPORT BEHAVIOUR]: Ignoring teleport action for {0} since no regions are known yet", bot.Name); + return; + } + + knownRegions = bot.Manager.RegionsKnown.Values.ToArray(); + } + + Simulator sourceRegion = bot.Client.Network.CurrentSim; + GridRegion destRegion = knownRegions[rng.Next(knownRegions.Length)]; + Vector3 destPosition = new Vector3(rng.Next(255), rng.Next(255), 50); + + m_log.DebugFormat( + "[TELEPORT BEHAVIOUR]: Teleporting {0} from {1} {2} to {3} {4}", + bot.Name, sourceRegion.Name, bot.Client.Self.SimPosition, destRegion.Name, destPosition); + + bot.Client.Self.Teleport(destRegion.RegionHandle, destPosition); + } + } +} \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 836d3f75f3..c67b3e43ab 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -153,6 +153,9 @@ namespace pCampBot if (behaviourSwitches.Contains("g")) behaviours.Add(new GrabbingBehaviour()); + if (behaviourSwitches.Contains("t")) + behaviours.Add(new TeleportBehaviour()); + StartBot(this, behaviours, firstName, lastName, password, loginUri); } } diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index 4d3b06d5bf..e7288d53cf 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -111,7 +111,7 @@ namespace pCampBot " -firstname first name for the bots\n" + " -lastname lastname for the bots. Each lastname will have _ appended, e.g. Ima Bot_0\n" + " -password password for the bots\n" + - " -b, behaviours behaviours for bots. Current options p (physics), g (grab). Comma separated, e.g. p,g. Default is p", + " -b, behaviours behaviours for bots. Current options p (physics), g (grab), t (teleport). Comma separated, e.g. p,g. Default is p", " -wear set appearance folder to load from (default: no)\n" + " -h, -help show this message" ); From ed7ddeecf2df370638feb0a83b70a0883a711650 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 23 Nov 2011 22:18:10 +0000 Subject: [PATCH 36/38] Print out what behaviours are active when pCampBot starts up --- .../pCampBot/Behaviours/GrabbingBehaviour.cs | 2 + .../pCampBot/Behaviours/PhysicsBehaviour.cs | 2 + .../pCampBot/Behaviours/TeleportBehaviour.cs | 2 + OpenSim/Tools/pCampBot/BotManager.cs | 39 +++++++++++++------ .../Tools/pCampBot/Interfaces/IBehaviour.cs | 9 +++++ 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs index 7084ab41de..0a6d5d2b97 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs @@ -41,6 +41,8 @@ namespace pCampBot /// public class GrabbingBehaviour : IBehaviour { + public string Name { get { return "Grabbing"; } } + public void Action(Bot bot) { Dictionary objects = bot.Objects; diff --git a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs index 3ce08bf617..f782bb507c 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs @@ -42,6 +42,8 @@ namespace pCampBot /// public class PhysicsBehaviour : IBehaviour { + public string Name { get { return "Physics"; } } + private string[] talkarray; public PhysicsBehaviour() diff --git a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs index 4624494ea6..fc2ed2c92a 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs @@ -42,6 +42,8 @@ namespace pCampBot { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public string Name { get { return "Teleport"; } } + public void Action(Bot bot) { Random rng = bot.Manager.Rng; diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index c67b3e43ab..29cb1ba98c 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Threading; using OpenMetaverse; @@ -48,7 +49,14 @@ namespace pCampBot { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Command console + /// protected CommandConsole m_console; + + /// + /// Created bots, whether active or inactive. + /// protected List m_lBot; /// @@ -56,6 +64,9 @@ namespace pCampBot /// public Random Rng { get; private set; } + /// + /// Overall configuration. + /// public IConfig Config { get; private set; } /// @@ -140,22 +151,26 @@ namespace pCampBot Array.ForEach( cs.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b)); + List behaviours = new List(); + + // Hard-coded for now + if (behaviourSwitches.Contains("p")) + behaviours.Add(new PhysicsBehaviour()); + + if (behaviourSwitches.Contains("g")) + behaviours.Add(new GrabbingBehaviour()); + + if (behaviourSwitches.Contains("t")) + behaviours.Add(new TeleportBehaviour()); + + MainConsole.Instance.OutputFormat( + "[BOT MANAGER]: Bots configured for behaviours {0}", + string.Join(",", behaviours.ConvertAll(b => b.Name).ToArray())); + for (int i = 0; i < botcount; i++) { string lastName = string.Format("{0}_{1}", lastNameStem, i); - List behaviours = new List(); - - // Hard-coded for now - if (behaviourSwitches.Contains("p")) - behaviours.Add(new PhysicsBehaviour()); - - if (behaviourSwitches.Contains("g")) - behaviours.Add(new GrabbingBehaviour()); - - if (behaviourSwitches.Contains("t")) - behaviours.Add(new TeleportBehaviour()); - StartBot(this, behaviours, firstName, lastName, password, loginUri); } } diff --git a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs index d4ae0f064b..912216f57a 100644 --- a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs @@ -31,6 +31,15 @@ namespace pCampBot.Interfaces { public interface IBehaviour { + /// + /// Name of this behaviour. + /// + string Name { get; } + + /// + /// Action to take when this behaviour is invoked. + /// + /// void Action(Bot bot); } } \ No newline at end of file From 0cb33a539812c69a6686c1b028318601793051a8 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Wed, 23 Nov 2011 16:09:11 -0800 Subject: [PATCH 37/38] Line endings --- .../World/AutoBackup/AutoBackupModuleState.cs | 202 +++++++++--------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs index 2db718c413..f9e118b23c 100644 --- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs +++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs @@ -23,104 +23,104 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - - -namespace OpenSim.Region.OptionalModules.World.AutoBackup -{ - /// AutoBackupModuleState: Auto-Backup state for one region (scene). - /// If you use this class in any way outside of AutoBackupModule, you should treat the class as opaque. - /// Since it is not part of the framework, you really should not rely upon it outside of the AutoBackupModule implementation. - /// - /// - public class AutoBackupModuleState - { - private Dictionary m_liveRequests = null; - - public AutoBackupModuleState() - { - this.Enabled = false; - this.BackupDir = "."; - this.BusyCheck = true; - this.Timer = null; - this.NamingType = NamingType.Time; - this.Script = null; - } - - public Dictionary LiveRequests - { - get { - return this.m_liveRequests ?? - (this.m_liveRequests = new Dictionary(1)); - } - } - - public bool Enabled - { - get; - set; - } - - public System.Timers.Timer Timer - { - get; - set; - } - - public double IntervalMinutes - { - get - { - if (this.Timer == null) - { - return -1.0; - } - else - { - return this.Timer.Interval / 60000.0; - } - } - } - - public bool BusyCheck - { - get; - set; - } - - public string Script - { - get; - set; - } - - public string BackupDir - { - get; - set; - } - - public NamingType NamingType - { - get; - set; - } - - public new string ToString() - { - string retval = ""; - - retval += "[AUTO BACKUP]: AutoBackup: " + (Enabled ? "ENABLED" : "DISABLED") + "\n"; - retval += "[AUTO BACKUP]: Interval: " + IntervalMinutes + " minutes" + "\n"; - retval += "[AUTO BACKUP]: Do Busy Check: " + (BusyCheck ? "Yes" : "No") + "\n"; - retval += "[AUTO BACKUP]: Naming Type: " + NamingType.ToString() + "\n"; - retval += "[AUTO BACKUP]: Backup Dir: " + BackupDir + "\n"; - retval += "[AUTO BACKUP]: Script: " + Script + "\n"; - return retval; - } - } -} - + */ + +using System; +using System.Collections.Generic; + + +namespace OpenSim.Region.OptionalModules.World.AutoBackup +{ + /// AutoBackupModuleState: Auto-Backup state for one region (scene). + /// If you use this class in any way outside of AutoBackupModule, you should treat the class as opaque. + /// Since it is not part of the framework, you really should not rely upon it outside of the AutoBackupModule implementation. + /// + /// + public class AutoBackupModuleState + { + private Dictionary m_liveRequests = null; + + public AutoBackupModuleState() + { + this.Enabled = false; + this.BackupDir = "."; + this.BusyCheck = true; + this.Timer = null; + this.NamingType = NamingType.Time; + this.Script = null; + } + + public Dictionary LiveRequests + { + get { + return this.m_liveRequests ?? + (this.m_liveRequests = new Dictionary(1)); + } + } + + public bool Enabled + { + get; + set; + } + + public System.Timers.Timer Timer + { + get; + set; + } + + public double IntervalMinutes + { + get + { + if (this.Timer == null) + { + return -1.0; + } + else + { + return this.Timer.Interval / 60000.0; + } + } + } + + public bool BusyCheck + { + get; + set; + } + + public string Script + { + get; + set; + } + + public string BackupDir + { + get; + set; + } + + public NamingType NamingType + { + get; + set; + } + + public new string ToString() + { + string retval = ""; + + retval += "[AUTO BACKUP]: AutoBackup: " + (Enabled ? "ENABLED" : "DISABLED") + "\n"; + retval += "[AUTO BACKUP]: Interval: " + IntervalMinutes + " minutes" + "\n"; + retval += "[AUTO BACKUP]: Do Busy Check: " + (BusyCheck ? "Yes" : "No") + "\n"; + retval += "[AUTO BACKUP]: Naming Type: " + NamingType.ToString() + "\n"; + retval += "[AUTO BACKUP]: Backup Dir: " + BackupDir + "\n"; + retval += "[AUTO BACKUP]: Script: " + Script + "\n"; + return retval; + } + } +} + From 89b2fb2ff491b97cdfa17b9b8a596dea77567b76 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Wed, 23 Nov 2011 16:41:30 -0800 Subject: [PATCH 38/38] Append asset ID to URL for storage requests to allow caching proxies to work with Simian --- .../Connectors/SimianGrid/SimianAssetServiceConnector.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs index d8089ac8b1..9573e215cd 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -334,7 +334,9 @@ namespace OpenSim.Services.Connectors.SimianGrid // Make the remote storage request try { - HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl); + // Simian does not require the asset ID to be in the URL because it's in the post data. + // By appending it to the URL also, we allow caching proxies (squid) to invalidate asset URLs + HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl + asset.FullID.ToString()); HttpWebResponse response = MultipartForm.Post(request, postParameters); using (Stream responseStream = response.GetResponseStream())