From 4c76a061c742aee0ab09db70ff1e074b68500668 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 24 Oct 2016 09:21:44 -0700 Subject: [PATCH 001/305] Flip master to 0.9.1 --- OpenSim/Framework/VersionInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/VersionInfo.cs b/OpenSim/Framework/VersionInfo.cs index 2e3c394187..7bb0351ea1 100644 --- a/OpenSim/Framework/VersionInfo.cs +++ b/OpenSim/Framework/VersionInfo.cs @@ -29,8 +29,8 @@ namespace OpenSim { public class VersionInfo { - public const string VersionNumber = "0.9.0.0"; - public const string AssemblyVersionNumber = "0.9.0.*"; + public const string VersionNumber = "0.9.1.0"; + public const string AssemblyVersionNumber = "0.9.1.*"; private const Flavour VERSION_FLAVOUR = Flavour.Dev; From db0c26814011764c381a432b5542e03433081811 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 25 Oct 2016 20:16:23 +0100 Subject: [PATCH 002/305] mantis 8041: check target user password on save/load IAR --- .../Avatar/Inventory/Archiver/InventoryArchiverModule.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs index 8d11d200c7..884741442e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs @@ -565,8 +565,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return null; } - return account; - /* try { string encpass = Util.Md5Hash(pass); @@ -587,7 +585,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_log.ErrorFormat("[INVENTORY ARCHIVER]: Could not authenticate password, {0}", e); return null; } - */ } /// From 7c4f2b048f4d74b3132486e8d7a6887c73d6562d Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 25 Oct 2016 20:44:41 +0100 Subject: [PATCH 003/305] ignore prims with shape type none on max size check for physics also on llStatus() --- .../ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 66cb30c5ec..85837e4eef 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -100,11 +100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected IScriptEngine m_ScriptEngine; protected SceneObjectPart m_host; - - /// - /// Used for script sleeps when we are using co-operative script termination. - /// - /// null if co-operative script termination is not active + /// /// The item that hosts this script /// @@ -1641,12 +1637,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (SceneObjectPart part in group.Parts) { + if (part.PhysicsShapeType == (byte)PhysicsShapeType.None) + continue; + if (part.Scale.X > World.m_maxPhys || part.Scale.Y > World.m_maxPhys || part.Scale.Z > World.m_maxPhys) { allow = false; break; } - if (checkShape && part.PhysicsShapeType != (byte)PhysicsShapeType.None) + if (checkShape) { if (--maxprims < 0) { From 9480da06b971e7ffa500c33399cdb2114a39637f Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 2 Nov 2016 21:42:32 +0000 Subject: [PATCH 004/305] only add a prim to physics in PhysicsShapeType if changing from type none. when viewers change ExtraPhysics parameters, send back the new values. --- .../ClientStack/Linden/UDP/LLClientView.cs | 1 - OpenSim/Region/Framework/Scenes/SceneGraph.cs | 2 +- .../Framework/Scenes/SceneObjectPart.cs | 113 ++++++++---------- 3 files changed, 51 insertions(+), 65 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index ad25bc89ac..17e44004c5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -2920,7 +2920,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP { m_log.Error("Unable to send part Physics Proprieties - exception: " + ex.ToString()); } - part.UpdatePhysRequired = false; } } diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 238ec8e863..1141f541dd 100755 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -1660,7 +1660,7 @@ namespace OpenSim.Region.Framework.Scenes if (part != null) { part.UpdateExtraPhysics(PhysData); - if (part.UpdatePhysRequired && remoteClient != null) + if (remoteClient != null) remoteClient.SendPartPhysicsProprieties(part); } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 06d767d11e..9d1dca2725 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1222,7 +1222,6 @@ namespace OpenSim.Region.Framework.Scenes } public UpdateRequired UpdateFlag { get; set; } - public bool UpdatePhysRequired { get; set; } /// /// Used for media on a prim. @@ -1637,7 +1636,6 @@ namespace OpenSim.Region.Framework.Scenes if(ParentGroup != null) ParentGroup.HasGroupChanged = true; ScheduleFullUpdateIfNone(); - UpdatePhysRequired = true; } } } @@ -1729,7 +1727,7 @@ namespace OpenSim.Region.Framework.Scenes set { byte oldv = m_physicsShapeType; - + if (value >= 0 && value <= (byte)PhysShapeType.convex) { if (value == (byte)PhysShapeType.none && ParentGroup != null && ParentGroup.RootPart == this) @@ -1748,28 +1746,21 @@ namespace OpenSim.Region.Framework.Scenes { ParentGroup.Scene.RemovePhysicalPrim(1); RemoveFromPhysics(); - Stop(); +// Stop(); } } else if (PhysActor == null) { - ApplyPhysics((uint)Flags, VolumeDetectActive, false); - UpdatePhysicsSubscribedEvents(); + if(oldv == (byte)PhysShapeType.none) + { + ApplyPhysics((uint)Flags, VolumeDetectActive, false); + UpdatePhysicsSubscribedEvents(); + } } else - { PhysActor.PhysicsShapeType = m_physicsShapeType; -// if (Shape.SculptEntry) -// CheckSculptAndLoad(); - } - if (ParentGroup != null) - ParentGroup.HasGroupChanged = true; - } - - if (m_physicsShapeType != value) - { - UpdatePhysRequired = true; + ParentGroup.HasGroupChanged = true; } } } @@ -1782,17 +1773,16 @@ namespace OpenSim.Region.Framework.Scenes if (value >=1 && value <= 22587.0) { m_density = value; - UpdatePhysRequired = true; + + ScheduleFullUpdateIfNone(); + + if (ParentGroup != null) + ParentGroup.HasGroupChanged = true; + + PhysicsActor pa = PhysActor; + if (pa != null) + pa.Density = m_density; } - - ScheduleFullUpdateIfNone(); - - if (ParentGroup != null) - ParentGroup.HasGroupChanged = true; - - PhysicsActor pa = PhysActor; - if (pa != null) - pa.Density = Density; } } @@ -1804,17 +1794,16 @@ namespace OpenSim.Region.Framework.Scenes if( value >= -1 && value <=28.0f) { m_gravitymod = value; - UpdatePhysRequired = true; + + ScheduleFullUpdateIfNone(); + + if (ParentGroup != null) + ParentGroup.HasGroupChanged = true; + + PhysicsActor pa = PhysActor; + if (pa != null) + pa.GravModifier = m_gravitymod; } - - ScheduleFullUpdateIfNone(); - - if (ParentGroup != null) - ParentGroup.HasGroupChanged = true; - - PhysicsActor pa = PhysActor; - if (pa != null) - pa.GravModifier = GravityModifier; } } @@ -1826,17 +1815,16 @@ namespace OpenSim.Region.Framework.Scenes if (value >= 0 && value <= 255.0f) { m_friction = value; - UpdatePhysRequired = true; + + ScheduleFullUpdateIfNone(); + + if (ParentGroup != null) + ParentGroup.HasGroupChanged = true; + + PhysicsActor pa = PhysActor; + if (pa != null) + pa.Friction = m_friction; } - - ScheduleFullUpdateIfNone(); - - if (ParentGroup != null) - ParentGroup.HasGroupChanged = true; - - PhysicsActor pa = PhysActor; - if (pa != null) - pa.Friction = Friction; } } @@ -1848,17 +1836,16 @@ namespace OpenSim.Region.Framework.Scenes if (value >= 0 && value <= 1.0f) { m_bounce = value; - UpdatePhysRequired = true; + + ScheduleFullUpdateIfNone(); + + if (ParentGroup != null) + ParentGroup.HasGroupChanged = true; + + PhysicsActor pa = PhysActor; + if (pa != null) + pa.Restitution = m_bounce; } - - ScheduleFullUpdateIfNone(); - - if (ParentGroup != null) - ParentGroup.HasGroupChanged = true; - - PhysicsActor pa = PhysActor; - if (pa != null) - pa.Restitution = Restitution; } } @@ -4541,24 +4528,24 @@ SendFullUpdateToClient(remoteClient, Position) ignores position parameter } } - public void UpdateExtraPhysics(ExtraPhysicsData physdata) { if (physdata.PhysShapeType == PhysShapeType.invalid || ParentGroup == null) return; - if (PhysicsShapeType != (byte)physdata.PhysShapeType) - { - PhysicsShapeType = (byte)physdata.PhysShapeType; - - } + byte newtype = (byte)physdata.PhysShapeType; + if (PhysicsShapeType != newtype) + PhysicsShapeType = newtype; if(Density != physdata.Density) Density = physdata.Density; + if(GravityModifier != physdata.GravitationModifier) GravityModifier = physdata.GravitationModifier; + if(Friction != physdata.Friction) Friction = physdata.Friction; + if(Restitution != physdata.Bounce) Restitution = physdata.Bounce; } From f29d5ad662387b97d9e881f28df584dc19fa8c07 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 2 Nov 2016 22:33:32 +0000 Subject: [PATCH 005/305] ubOde: if a mesh does not contain data for shape type PRIM, dont collide as convex as before but just don't collide matching the type NONE viewers display in this case --- OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs index ff10e7f35b..bcd1530302 100644 --- a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs +++ b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs @@ -443,6 +443,11 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing if (physicsParms != null) usemesh = true; + else + { + m_log.WarnFormat("[MESH]: Data for PRIM shape type not found for prim {0}",primName); + return false; + } } if(!usemesh && (map.ContainsKey("physics_convex"))) @@ -451,7 +456,7 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing if (physicsParms == null) { - m_log.WarnFormat("[MESH]: unknown mesh type for {0}",primName); + m_log.WarnFormat("[MESH]: unknown mesh type for prim {0}",primName); return false; } From 73b20c2ca25e5ee6f1b6673ef764c4da40625ec3 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 3 Nov 2016 12:58:43 +0000 Subject: [PATCH 006/305] XEngine: make calls to gc.collect on region startup scripts loading a configurable option, since it is very slow operation --- .../Region/ScriptEngine/XEngine/XEngine.cs | 12 +++++------ bin/OpenSim.ini.example | 7 +++++++ bin/OpenSimDefaults.ini | 21 +++++++++++++------ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 30389152f0..e12f8509bc 100755 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -110,6 +110,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine private int m_ScriptFailCount; // Number of script fails since compile queue was last empty private string m_ScriptErrorMessage; private bool m_AppDomainLoading; + private bool m_CompactMemOnLoad; private Dictionary m_ScriptErrors = new Dictionary(); @@ -301,8 +302,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300); m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144); m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000; - m_AppDomainLoading = m_ScriptConfig.GetBoolean("AppDomainLoading", true); - + m_AppDomainLoading = m_ScriptConfig.GetBoolean("AppDomainLoading", false); + m_CompactMemOnLoad = m_ScriptConfig.GetBoolean("CompactMemOnLoad", false); m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000; @@ -1278,10 +1279,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine } } - // do not load a assembly on top of a lot of to release memory - // also yield a bit - // only if logins disable since causes a lot of rubber banding - if(!m_Scene.LoginsEnabled) + // optionaly do not load a assembly on top of a lot of to release memory + // only if logins disable since causes a lot of rubber banding + if(m_CompactMemOnLoad && !m_Scene.LoginsEnabled) GC.Collect(2); ScriptInstance instance = null; diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 4b83751daf..dce32bf07a 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -925,6 +925,13 @@ ;; by scripts have changed. ; DeleteScriptsOnStartup = true + ;# {CompactMemOnLoad} {} {compacts memory on each script load at startup?} {true false} false + ;; forces calls to memory garbage collector before loading each script DLL during region startup. + ;; Peek memory usage is reduced and region starts with a more compacted memory allocation. + ;; But this costs a lot of time, so region load will take a lot longer. + ;; it is more usefull if there are no previously compiled scripts DLLs (as with DeleteScriptsOnStartup = true) + ;CompactMemOnLoad = false + ;# {DefaultCompileLanguage} {Enabled:true} {Default script language?} {lsl vb cs} lsl ;; Default language for scripts ; DefaultCompileLanguage = "lsl" diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index e846e73e0e..cb320a260d 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1696,14 +1696,23 @@ ; this may only be a problem if regions stay alive for a long time with lots of scripts added or edited. ; at this time some mono versions seem to have problems with the true option ; so default is now false until a fix is found - AppDomainLoading = false + ; AppDomainLoading = false - ; 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 = false + ; 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. + ; It should be true on first run after updating opensim binary version + ; after first run you can change to false. + ; You can also set it to false and delete the script DLLs by hand + ; This does not delete cached scripts state. + ; DeleteScriptsOnStartup = true + ; CompactMemOnLoad forces calls to memory garbage collector before loading each script binary + ; forces calls to memory garbage collector before loading each script DLL during region startup. + ; Peek memory usage is reduced and region starts with a more compacted memory allocation. + ; But this costs a lot of time, so region load will take a lot longer. + ; it is more usefull if there are no previously compiled scripts DLLs (or DeleteScriptsOnStartup = true) + ; CompactMemOnLoad = false + ; Controls whether scripts are stopped by aborting their threads externally (abort) ; or by co-operative checks inserted by OpenSimulator into compiled script (co-op). ; co-op will be more stable as aborting threads can cause instability. From 4b326f86917e1fd3b8d20277d2e6ff0a1a14f3e8 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 3 Nov 2016 14:00:45 +0000 Subject: [PATCH 007/305] fix some coments, thanks Austin Tate --- bin/OpenSim.ini.example | 2 +- bin/OpenSimDefaults.ini | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index dce32bf07a..961c141362 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -927,7 +927,7 @@ ;# {CompactMemOnLoad} {} {compacts memory on each script load at startup?} {true false} false ;; forces calls to memory garbage collector before loading each script DLL during region startup. - ;; Peek memory usage is reduced and region starts with a more compacted memory allocation. + ;; Peak memory usage is reduced and region starts with a more compacted memory allocation. ;; But this costs a lot of time, so region load will take a lot longer. ;; it is more usefull if there are no previously compiled scripts DLLs (as with DeleteScriptsOnStartup = true) ;CompactMemOnLoad = false diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index cb320a260d..c4a01a6ef1 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1706,9 +1706,9 @@ ; This does not delete cached scripts state. ; DeleteScriptsOnStartup = true - ; CompactMemOnLoad forces calls to memory garbage collector before loading each script binary + ; CompactMemOnLoad ; forces calls to memory garbage collector before loading each script DLL during region startup. - ; Peek memory usage is reduced and region starts with a more compacted memory allocation. + ; Peak memory usage is reduced and region starts with a more compacted memory allocation. ; But this costs a lot of time, so region load will take a lot longer. ; it is more usefull if there are no previously compiled scripts DLLs (or DeleteScriptsOnStartup = true) ; CompactMemOnLoad = false From d2e380e81e549ccce316ef873502f66ba6806642 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 3 Nov 2016 16:56:09 +0000 Subject: [PATCH 008/305] on get asset with callback, do the callback even if asset not found. This is needed on same cases --- .../Asset/AssetServicesConnector.cs | 53 +++++++------------ 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index 99119d33ee..a6e8eb424b 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -347,51 +347,34 @@ namespace OpenSim.Services.Connectors string uri = r.uri; string id = r.id; - bool success = false; try { AssetBase a = SynchronousRestObjectRequester.MakeRequest("GET", uri, 0, 30000, m_Auth); - if (a != null) + + if (a != null && m_Cache != null) + m_Cache.Cache(a); + + List handlers; + lock (m_AssetHandlers) { - if (m_Cache != null) - m_Cache.Cache(a); + handlers = m_AssetHandlers[id]; + m_AssetHandlers.Remove(id); + } - List handlers; - lock (m_AssetHandlers) + if(handlers != null) + { + Util.FireAndForget(x => { - handlers = m_AssetHandlers[id]; - m_AssetHandlers.Remove(id); - } - - if(handlers != null) - { - Util.FireAndForget(x => + foreach (AssetRetrievedEx h in handlers) { - foreach (AssetRetrievedEx h in handlers) - { - try { h.Invoke(a); } - catch { } - } - handlers.Clear(); - }); - } - success = true; - } - } - finally - { - if (!success) - { - List handlers; - lock (m_AssetHandlers) - { - handlers = m_AssetHandlers[id]; - m_AssetHandlers.Remove(id); - } - if (handlers != null) + try { h.Invoke(a); } + catch { } + } handlers.Clear(); + }); } } + catch { } } } From b0f87fba1c4238a042a0b7112d792815dd10b737 Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Fri, 4 Nov 2016 06:24:56 +0100 Subject: [PATCH 009/305] Implementation of new LSL function: list llGetAttachedList(key avatar); It also returns HUDs' keys. Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- .../Shared/Api/Implementation/LSL_Api.cs | 26 +++++++++++++++++++ .../Shared/Api/Interface/ILSL_Api.cs | 1 + .../Shared/Api/Runtime/LSL_Stub.cs | 5 ++++ 3 files changed, 32 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 85837e4eef..5f8734758c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -7022,6 +7022,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return m_host.ParentGroup.AttachmentPoint; } + public LSL_List llGetAttachedList(string id) + { + m_host.AddScriptLPS(1); + + LSL_List AttachmentsList = new LSL_List(); + + ScenePresence av = World.GetScenePresence((UUID)id); + + string NOT_FOUND = "NOT_FOUND"; + string NOT_ON_REGION = "NOT ON REGION"; + + if (av == null) + return new LSL_List(NOT_FOUND); + if (av.IsChildAgent) + return new LSL_List(NOT_ON_REGION); + + List AttachmentsKeys; + + AttachmentsKeys = av.GetAttachments(); + + foreach (SceneObjectGroup AttachmentKey in AttachmentsKeys) + AttachmentsList.Add(new LSL_Key(AttachmentKey.FromItemID.ToString())); + + return AttachmentsList; + } + public virtual LSL_Integer llGetFreeMemory() { m_host.AddScriptLPS(1); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index 8b8638c935..3d1482d921 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -116,6 +116,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_String llGetAnimation(string id); LSL_List llGetAnimationList(string id); LSL_Integer llGetAttached(); + LSL_List llGetAttachedList(string id); LSL_List llGetBoundingBox(string obj); LSL_Vector llGetCameraPos(); LSL_Rotation llGetCameraRot(); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index cea66d2c5f..2769712f2a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -426,6 +426,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llGetAttached(); } + public LSL_List llGetAttachedList(string id) + { + return m_LSL_Functions.llGetAttachedList(id); + } + public LSL_List llGetBoundingBox(string obj) { return m_LSL_Functions.llGetBoundingBox(obj); From 9b78eb20c0a7b1907fec67dc2104756f6d2a96d5 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 4 Nov 2016 11:58:52 +0000 Subject: [PATCH 010/305] by design HUD objects are private --- .../Shared/Api/Implementation/LSL_Api.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 5f8734758c..ced81ada3e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -7026,24 +7026,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - LSL_List AttachmentsList = new LSL_List(); - ScenePresence av = World.GetScenePresence((UUID)id); - string NOT_FOUND = "NOT_FOUND"; - string NOT_ON_REGION = "NOT ON REGION"; + if (av == null || av.IsDeleted) + return new LSL_List("NOT_FOUND"); - if (av == null) - return new LSL_List(NOT_FOUND); - if (av.IsChildAgent) - return new LSL_List(NOT_ON_REGION); + if (av.IsChildAgent || av.IsInTransit) + return new LSL_List("NOT_ON_REGION"); - List AttachmentsKeys; + LSL_List AttachmentsList = new LSL_List(); + List Attachments; - AttachmentsKeys = av.GetAttachments(); + Attachments = av.GetAttachments(); - foreach (SceneObjectGroup AttachmentKey in AttachmentsKeys) - AttachmentsList.Add(new LSL_Key(AttachmentKey.FromItemID.ToString())); + foreach (SceneObjectGroup Attachment in Attachments) + { + if(Attachment.HasPrivateAttachmentPoint) + continue; + AttachmentsList.Add(new LSL_Key(Attachment.UUID.ToString())); + } return AttachmentsList; } From 72db2d064a7511c319888f46a5b7242c794bf5f9 Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Sat, 5 Nov 2016 03:19:15 +0100 Subject: [PATCH 011/305] It looks, that attachments show console command incorrectly returns Item ID. In fact, FromItem ID is returned. So I have added proper Item ID to be returned. There are cases, that FromItem ID is also useful, so I keep it for compatibility. Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- .../Attachments/AttachmentsCommandModule.cs | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs index 0333747fff..a147e9b038 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs @@ -144,14 +144,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments private void GetAttachmentsReport(ScenePresence sp, StringBuilder sb) { - sb.AppendFormat("Attachments for {0}\n", sp.Name); + sb.AppendFormat("Attachments for {0}\n\n", sp.Name); - ConsoleDisplayTable ct = new ConsoleDisplayTable() { Indent = 2 }; - ct.Columns.Add(new ConsoleDisplayTableColumn("Attachment Name", 50)); - ct.Columns.Add(new ConsoleDisplayTableColumn("Local ID", 10)); - ct.Columns.Add(new ConsoleDisplayTableColumn("Item ID", 36)); - ct.Columns.Add(new ConsoleDisplayTableColumn("Attach Point", 14)); - ct.Columns.Add(new ConsoleDisplayTableColumn("Position", 15)); + ConsoleDisplayList ct = new ConsoleDisplayList(); // sb.AppendFormat( // " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", @@ -177,17 +172,17 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments // attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID, // (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos); - ct.AddRow( - attachmentObject.Name, - attachmentObject.LocalId, - attachmentObject.FromItemID, - ((AttachmentPoint)attachmentObject.AttachmentPoint), - attachmentObject.RootPart.AttachedPos); + ct.Indent = 2; + ct.AddRow("Attachment Name", attachmentObject.Name); + ct.AddRow("Local ID", attachmentObject.LocalId); + ct.AddRow("Item ID", attachmentObject.UUID); + ct.AddRow("From Item ID", attachmentObject.FromItemID); + ct.AddRow("Attach Point", ((AttachmentPoint)attachmentObject.AttachmentPoint)); + ct.AddRow("Position", attachmentObject.RootPart.AttachedPos + "\n\n"); // } } ct.AddToStringBuilder(sb); - sb.Append("\n"); } } } \ No newline at end of file From be0a957363f3fda72fab94b427afd30b8af46785 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 5 Nov 2016 15:42:37 +0000 Subject: [PATCH 012/305] add a few lsl constants and move some around --- .../Shared/Api/Runtime/LSL_Constants.cs | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 4a8e885c59..1a3de1e708 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -336,11 +336,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int ROTATE = 32; public const int SCALE = 64; public const int ALL_SIDES = -1; + + // LINK flags public const int LINK_SET = -1; + public const int LINK_TRUEROOT = 0; // possible this should had been ROOT all the time public const int LINK_ROOT = 1; public const int LINK_ALL_OTHERS = -2; public const int LINK_ALL_CHILDREN = -3; public const int LINK_THIS = -4; + public const int CHANGED_INVENTORY = 1; public const int CHANGED_COLOR = 2; public const int CHANGED_SHAPE = 4; @@ -356,6 +360,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int CHANGED_MEDIA = 2048; public const int CHANGED_ANIMATION = 16384; public const int CHANGED_POSITION = 32768; + public const int TYPE_INVALID = 0; public const int TYPE_INTEGER = 1; public const int TYPE_FLOAT = 2; @@ -389,6 +394,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int CONTENT_TYPE_FORM = 7; //application/x-www-form-urlencoded public const int CONTENT_TYPE_RSS = 8; //application/rss+xml + //parameters comand flags public const int PRIM_MATERIAL = 2; public const int PRIM_PHYSICS = 3; public const int PRIM_TEMP_ON_REZ = 4; @@ -397,19 +403,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_SIZE = 7; public const int PRIM_ROTATION = 8; public const int PRIM_TYPE = 9; + // gap 10-16 public const int PRIM_TEXTURE = 17; public const int PRIM_COLOR = 18; public const int PRIM_BUMP_SHINY = 19; public const int PRIM_FULLBRIGHT = 20; public const int PRIM_FLEXIBLE = 21; public const int PRIM_TEXGEN = 22; - public const int PRIM_CAST_SHADOWS = 24; // Not implemented, here for completeness sake public const int PRIM_POINT_LIGHT = 23; // Huh? + public const int PRIM_CAST_SHADOWS = 24; // Not implemented, here for completeness sake public const int PRIM_GLOW = 25; public const int PRIM_TEXT = 26; public const int PRIM_NAME = 27; public const int PRIM_DESC = 28; public const int PRIM_ROT_LOCAL = 29; + public const int PRIM_PHYSICS_SHAPE_TYPE = 30; + public const int PRIM_PHYSICS_MATERIAL = 31; // aparently not SL public const int PRIM_OMEGA = 32; public const int PRIM_POS_LOCAL = 33; public const int PRIM_LINK_TARGET = 34; @@ -417,6 +426,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_SPECULAR = 36; public const int PRIM_NORMAL = 37; public const int PRIM_ALPHA_MODE = 38; + public const int PRIM_ALLOW_UNSIT = 39; // experiences related. Unsuport + public const int PRIM_SCRIPTED_SIT_ONLY = 40; // experiences related. Unsuport + public const int PRIM_SIT_TARGET = 40; + + + // parameters public const int PRIM_TEXGEN_DEFAULT = 0; public const int PRIM_TEXGEN_PLANAR = 1; @@ -473,6 +488,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_SCULPT_FLAG_INVERT = 64; public const int PRIM_SCULPT_FLAG_MIRROR = 128; + public const int PRIM_PHYSICS_SHAPE_PRIM = 0; + public const int PRIM_PHYSICS_SHAPE_NONE = 1; + public const int PRIM_PHYSICS_SHAPE_CONVEX = 2; + public const int PROFILE_NONE = 0; public const int PROFILE_SCRIPT_MEMORY = 1; @@ -701,12 +720,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_MEDIA_PERM_GROUP = 2; public const int PRIM_MEDIA_PERM_ANYONE = 4; - public const int PRIM_PHYSICS_SHAPE_TYPE = 30; - public const int PRIM_PHYSICS_SHAPE_PRIM = 0; - public const int PRIM_PHYSICS_SHAPE_CONVEX = 2; - public const int PRIM_PHYSICS_SHAPE_NONE = 1; - - public const int PRIM_PHYSICS_MATERIAL = 31; public const int DENSITY = 1; public const int FRICTION = 2; public const int RESTITUTION = 4; From 060350832ae0be015182a3516a718dfdf030b56c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 5 Nov 2016 16:50:41 +0000 Subject: [PATCH 013/305] add suport for PRIM_SIT_TARGET on get(link)PrimitveParameters and fix typos --- .../Shared/Api/Implementation/LSL_Api.cs | 27 ++++++++++++++----- .../Shared/Api/Runtime/LSL_Constants.cs | 9 +++---- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index ced81ada3e..91b49cdbb9 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -662,15 +662,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api List ret = new List(); if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) return ret; - ret.Add(part); switch (linkType) { case ScriptBaseClass.LINK_SET: return new List(part.ParentGroup.Parts); - case ScriptBaseClass.LINK_ROOT: - ret = new List(); + case ScriptBaseClass.LINK_ROOT: ret.Add(part.ParentGroup.RootPart); return ret; @@ -690,16 +688,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return ret; case ScriptBaseClass.LINK_THIS: + ret.Add(part); return ret; default: if (linkType < 0) - return new List(); + return ret; SceneObjectPart target = part.ParentGroup.GetLinkNumPart(linkType); if (target == null) - return new List(); - ret = new List(); + return ret; ret.Add(target); return ret; } @@ -11182,7 +11180,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api res.Add(new LSL_Float(spin)); res.Add(new LSL_Float(gain)); break; - + + case (int)ScriptBaseClass.PRIM_SIT_TARGET: + if(part.IsSitTargetSet) + { + res.Add(new LSL_Integer(1)); + res.Add(new LSL_Vector(part.SitTargetPosition)); + res.Add(new LSL_Rotation(part.SitTargetOrientation)); + } + else + { + res.Add(new LSL_Integer(0)); + res.Add(new LSL_Vector(Vector3.Zero)); + res.Add(new LSL_Rotation(Quaternion.Identity)); + } + break; + case (int)ScriptBaseClass.PRIM_LINK_TARGET: // TODO: Should be issuing a runtime script warning in this case. diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 1a3de1e708..bc4d20cc02 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -339,7 +339,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase // LINK flags public const int LINK_SET = -1; - public const int LINK_TRUEROOT = 0; // possible this should had been ROOT all the time public const int LINK_ROOT = 1; public const int LINK_ALL_OTHERS = -2; public const int LINK_ALL_CHILDREN = -3; @@ -418,7 +417,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_DESC = 28; public const int PRIM_ROT_LOCAL = 29; public const int PRIM_PHYSICS_SHAPE_TYPE = 30; - public const int PRIM_PHYSICS_MATERIAL = 31; // aparently not SL + public const int PRIM_PHYSICS_MATERIAL = 31; // apparently not on SL wiki public const int PRIM_OMEGA = 32; public const int PRIM_POS_LOCAL = 33; public const int PRIM_LINK_TARGET = 34; @@ -426,9 +425,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_SPECULAR = 36; public const int PRIM_NORMAL = 37; public const int PRIM_ALPHA_MODE = 38; - public const int PRIM_ALLOW_UNSIT = 39; // experiences related. Unsuport - public const int PRIM_SCRIPTED_SIT_ONLY = 40; // experiences related. Unsuport - public const int PRIM_SIT_TARGET = 40; + public const int PRIM_ALLOW_UNSIT = 39; // experiences related. unsupported + public const int PRIM_SCRIPTED_SIT_ONLY = 40; // experiences related. unsupported + public const int PRIM_SIT_TARGET = 41; // parameters From 1c7b688db4e78c24058a2f7e24afca2eb751bec4 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 5 Nov 2016 18:28:30 +0000 Subject: [PATCH 014/305] add suport for PRIM_SIT_TARGET on Set(link)PrimitveParameters. This may not be SL compatible. hack: to let active work with zero offset and rotation add a little Z value to offset --- .../Shared/Api/Implementation/LSL_Api.cs | 48 +++++++++++++++++++ .../Region/ScriptEngine/Shared/LSL_Types.cs | 8 +++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 91b49cdbb9..ba22201941 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -10084,6 +10084,53 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.UpdateSlice((float)slice.x, (float)slice.y); break; + case ScriptBaseClass.PRIM_SIT_TARGET: + if (remain < 3) + return new LSL_List(); + + int active; + try + { + active = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SIT_TARGET: arg #{1} - parameter 1 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + LSL_Vector offset; + try + { + offset = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SIT_TARGET: arg #{1} - parameter 2 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + LSL_Rotation sitrot; + try + { + sitrot = rules.GetQuaternionItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SIT_TARGET: arg #{1} - parameter 3 must be rotation", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + // not SL compatible since we don't have a independent flag to control active target but use the values of offset and rotation + if(active == 1) + { + if(offset.x == 0 && offset.y == 0 && offset.z == 0 && sitrot.s == 1.0) + offset.z = 1e-5f; // hack + SitTarget(part,offset,sitrot); + } + else if(active == 0) + SitTarget(part, Vector3.Zero , Quaternion.Identity); + + break; + case ScriptBaseClass.PRIM_LINK_TARGET: if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless. return new LSL_List(); @@ -15932,6 +15979,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case (int)ScriptBaseClass.PRIM_TEXT: case (int)ScriptBaseClass.PRIM_BUMP_SHINY: case (int)ScriptBaseClass.PRIM_OMEGA: + case (int)ScriptBaseClass.PRIM_SIT_TARGET: if (remain < 3) return new LSL_List(); idx += 3; diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index 9fb1e2cf8c..c36e7c6c04 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -704,12 +704,16 @@ namespace OpenSim.Region.ScriptEngine.Shared { if (Data[itemIndex] is LSL_Types.Quaternion) { - return (LSL_Types.Quaternion)Data[itemIndex]; + LSL_Types.Quaternion q = (LSL_Types.Quaternion)Data[itemIndex]; + q.Normalize(); + return q; } else if(Data[itemIndex] is OpenMetaverse.Quaternion) { - return new LSL_Types.Quaternion( + LSL_Types.Quaternion q = new LSL_Types.Quaternion( (OpenMetaverse.Quaternion)Data[itemIndex]); + q.Normalize(); + return q; } else { From 4b0457b2d30282643d9402e1fcf751a4bb9303fe Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 5 Nov 2016 18:44:45 +0000 Subject: [PATCH 015/305] Regression, really ??? --- OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs index 71b88bcce6..20bbd722af 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs @@ -270,6 +270,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests TestHelpers.InMethod(); LSL_Types.Quaternion testValue = new LSL_Types.Quaternion(12.64, 59.43723, 765.3421, 4.00987); + // make that nonesense a quartenion + testValue.Normalize(); LSL_Types.list testList = new LSL_Types.list(testValue); Assert.AreEqual(testValue, testList.GetQuaternionItem(0)); From 22d20dbf17ca01128994d188721e8e4153700ff6 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 5 Nov 2016 19:17:25 +0000 Subject: [PATCH 016/305] disable bad/broken throttle options --- .../Region/ClientStack/Linden/UDP/ThrottleRates.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs index 076551fcb0..4448b7239c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs @@ -100,11 +100,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP BrustTime = (float)throttleConfig.GetInt("client_throttle_burtsTimeMS", 10); BrustTime *= 1e-3f; - AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); + // Adaptive is broken +// AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); + AdaptiveThrottlesEnabled = false; MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000); - CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f); - CannibalizeTextureRate = Util.Clamp(CannibalizeTextureRate,0.0, 0.9); + // http textures do use udp bandwith setting +// CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f); +// CannibalizeTextureRate = Util.Clamp(CannibalizeTextureRate,0.0, 0.9); + CannibalizeTextureRate = 0f; + } catch (Exception) { } } From 8cc8d15f950657d4d021fc81d14a8715007e7bb4 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 5 Nov 2016 20:14:11 +0000 Subject: [PATCH 017/305] some types may already be native in MOD_Api ConvertFromLSL --- OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs | 2 +- .../ScriptEngine/Shared/Api/Implementation/MOD_Api.cs | 6 +++++- .../Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs index 4448b7239c..a476b919a5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs @@ -105,7 +105,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AdaptiveThrottlesEnabled = false; MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000); - // http textures do use udp bandwith setting + // http textures do use udp bandwidth setting // CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f); // CannibalizeTextureRate = Util.Clamp(CannibalizeTextureRate,0.0, 0.9); CannibalizeTextureRate = 0f; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index 7bd4fa7cae..1e260367bf 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs @@ -365,8 +365,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// protected object ConvertFromLSL(object lslparm, Type type, string fname) { + + if(lslparm.GetType() == type) + return lslparm; + // ---------- String ---------- - if (lslparm is LSL_String) + else if (lslparm is LSL_String) { if (type == typeof(string)) return (string)(LSL_String)lslparm; diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs index 20bbd722af..fe2113bd56 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs @@ -270,7 +270,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests TestHelpers.InMethod(); LSL_Types.Quaternion testValue = new LSL_Types.Quaternion(12.64, 59.43723, 765.3421, 4.00987); - // make that nonesense a quartenion + // make that nonsense a quaternion testValue.Normalize(); LSL_Types.list testList = new LSL_Types.list(testValue); From 6bc76860d185ba6296f268373ccfea6375fff611 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 5 Nov 2016 23:56:55 +0000 Subject: [PATCH 018/305] avoid a null ref, few changes to udp updates send --- .../ClientStack/Linden/UDP/LLClientView.cs | 32 +++---------------- .../ClientStack/Linden/UDP/LLUDPClient.cs | 30 ++++++----------- .../DataSnapshot/LandSnapshot.cs | 5 ++- 3 files changed, 19 insertions(+), 48 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 17e44004c5..276b36724d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -4632,28 +4632,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) { -// if (!m_udpServer.IsRunningOutbound) -// return; - if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) { -// if (!m_udpServer.IsRunningOutbound) -// return; -/* - if (m_maxUpdates == 0 || m_LastQueueFill == 0) - { - m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; - } - else - { - if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) - m_maxUpdates += 5; - else - m_maxUpdates = m_maxUpdates >> 1; - } - m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); - m_LastQueueFill = Util.EnvironmentTickCount(); -*/ int maxUpdateBytes = m_udpClient.GetCatBytesCanSend(ThrottleOutPacketType.Task, 30); if (m_entityUpdates.Count > 0) @@ -4669,23 +4649,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories) { - bool hasUpdates = false; - if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) { if (m_entityUpdates.Count > 0) - hasUpdates = true; - else if (m_entityProps.Count > 0) - hasUpdates = true; + return true; + if (m_entityProps.Count > 0) + return true; } if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) { if (ImageManager.HasUpdates()) - hasUpdates = true; + return true; } - return hasUpdates; + return false; } public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 4e68a9b1c8..246f003dd2 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -166,7 +166,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Total number of sent packets that we have reported to the OnPacketStats event(s) private int m_packetsSentReported; /// Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired - private int m_nextOnQueueEmpty = 1; + private double m_nextOnQueueEmpty = 0; /// Throttle bucket for this agent's connection private readonly AdaptiveTokenBucket m_throttleClient; @@ -771,7 +771,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP RTO = Math.Min(RTO * 2, m_maxRTO); } - const int MIN_CALLBACK_MS = 20; + const double MIN_CALLBACK_MS = 20.0; + private bool m_isQueueEmptyRunning; /// /// Does an early check to see if this queue empty callback is already @@ -782,35 +783,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (!m_isQueueEmptyRunning) { - int start = Environment.TickCount & Int32.MaxValue; + if (!HasUpdates(categories)) + return; + double start = Util.GetTimeStampMS(); if (start < m_nextOnQueueEmpty) return; m_isQueueEmptyRunning = true; - m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; - if (m_nextOnQueueEmpty == 0) - m_nextOnQueueEmpty = 1; - if (HasUpdates(categories)) - { - if (!m_udpServer.OqrEngine.IsRunning) - { - // Asynchronously run the callback - Util.FireAndForget(FireQueueEmpty, categories, "LLUDPClient.BeginFireQueueEmpty"); - } - else - { - m_udpServer.OqrEngine.QueueJob(AgentID.ToString(), () => FireQueueEmpty(categories)); - } - } + // Asynchronously run the callback + if (m_udpServer.OqrEngine.IsRunning) + m_udpServer.OqrEngine.QueueJob(AgentID.ToString(), () => FireQueueEmpty(categories)); else - m_isQueueEmptyRunning = false; + Util.FireAndForget(FireQueueEmpty, categories, "LLUDPClient.BeginFireQueueEmpty"); } } - private bool m_isQueueEmptyRunning; /// diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs index b8c90cd5a1..5c791e6e76 100644 --- a/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs +++ b/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs @@ -120,12 +120,15 @@ namespace OpenSim.Region.DataSnapshot.Providers public XmlNode RequestSnapshotData(XmlDocument nodeFactory) { + XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "parceldata", ""); ILandChannel landChannel = m_scene.LandChannel; + if(landChannel == null) + return parent; + List parcels = landChannel.AllParcels(); IDwellModule dwellModule = m_scene.RequestModuleInterface(); - XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "parceldata", ""); if (parcels != null) { From d07f48605f90a0f0485d0ac11ec5641bbb88a28a Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 6 Nov 2016 02:43:33 +0000 Subject: [PATCH 019/305] change llGetTime() source clock --- .../Shared/Api/Implementation/LSL_Api.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index ba22201941..02a9ebcab5 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -113,7 +113,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected float m_MinTimerInterval = 0.5f; protected float m_recoilScaleFactor = 0.0f; - protected DateTime m_timer = DateTime.Now; + protected double m_timer = Util.GetTimeStampMS(); protected bool m_waitingForScriptAnswer = false; protected bool m_automaticLinkPermission = false; protected IMessageTransferModule m_TransferModule = null; @@ -3048,22 +3048,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float llGetTime() { m_host.AddScriptLPS(1); - TimeSpan ScriptTime = DateTime.Now - m_timer; - return (double)(ScriptTime.TotalMilliseconds / 1000); + double ScriptTime = Util.GetTimeStampMS() - m_timer; + return (ScriptTime / 1000.0); } public void llResetTime() { m_host.AddScriptLPS(1); - m_timer = DateTime.Now; + m_timer = Util.GetTimeStampMS(); } public LSL_Float llGetAndResetTime() { m_host.AddScriptLPS(1); - TimeSpan ScriptTime = DateTime.Now - m_timer; - m_timer = DateTime.Now; - return (double)(ScriptTime.TotalMilliseconds / 1000); + double now = Util.GetTimeStampMS(); + double ScriptTime = now - m_timer; + m_timer = now; + return (ScriptTime / 1000.0); } public void llSound(string sound, double volume, int queue, int loop) @@ -14544,7 +14545,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL); bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL); - if (World.SupportsRayCastFiltered()) { if (dist == 0) @@ -14650,7 +14650,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { return a.Depth.CompareTo(b.Depth); }); - + int values = 0; SceneObjectGroup thisgrp = m_host.ParentGroup; @@ -14704,7 +14704,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } list.Add(new LSL_Integer(values)); - return list; } From 014cd1ab428feff96484c666694c33822344269e Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 6 Nov 2016 03:53:12 +0000 Subject: [PATCH 020/305] restrict ubOde castray with terrain range only on horizontal plane, let it find physical avatars. --- .../ubOde/ODERayCastRequestManager.cs | 11 +++++++++- .../Shared/Api/Implementation/LSL_Api.cs | 22 +++++++++++-------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODERayCastRequestManager.cs b/OpenSim/Region/PhysicsModules/ubOde/ODERayCastRequestManager.cs index b82d5930b4..adefd5edf5 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODERayCastRequestManager.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODERayCastRequestManager.cs @@ -317,8 +317,17 @@ namespace OpenSim.Region.PhysicsModule.ubOde // current ode land to ray collisions is very bad // so for now limit its range badly if (req.length > 60.0f) - d.GeomRaySetLength(ray, 60.0f); + { + Vector3 t = req.Normal * req.length; + float tmp = t.X * t.X + t.Y * t.Y; + if(tmp > 2500) + { + float tmp2 = req.length * req.length - tmp + 2500; + tmp2 = (float)Math.Sqrt(tmp2); + d.GeomRaySetLength(ray, tmp2); + } + } d.SpaceCollide2(ray, m_scene.GroundSpace, IntPtr.Zero, nearCallback); } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 02a9ebcab5..33d5757b14 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -14216,18 +14216,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return false; } - private ContactResult[] AvatarIntersection(Vector3 rayStart, Vector3 rayEnd) + private ContactResult[] AvatarIntersection(Vector3 rayStart, Vector3 rayEnd, bool skipPhys) { List contacts = new List(); Vector3 ab = rayEnd - rayStart; + float ablen = ab.Length(); World.ForEachScenePresence(delegate(ScenePresence sp) { - Vector3 ac = sp.AbsolutePosition - rayStart; -// Vector3 bc = sp.AbsolutePosition - rayEnd; + if(skipPhys && sp.PhysicsActor != null) + return; - double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); + Vector3 ac = sp.AbsolutePosition - rayStart; + + double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / ablen); if (d > 1.5) return; @@ -14553,8 +14556,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api RayFilterFlags rayfilter = RayFilterFlags.BackFaceCull; if (checkTerrain) rayfilter |= RayFilterFlags.land; -// if (checkAgents) -// rayfilter |= RayFilterFlags.agent; + if (checkAgents) + rayfilter |= RayFilterFlags.agent; if (checkPhysical) rayfilter |= RayFilterFlags.physical; if (checkNonPhysical) @@ -14578,18 +14581,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api object physresults; physresults = World.RayCastFiltered(rayStart, direction, dist, physcount, rayfilter); +/* if (physresults == null) { list.Add(new LSL_Integer(-3)); // timeout error return list; } - +*/ results = (List)physresults; // for now physics doesn't detect sitted avatars so do it outside physics if (checkAgents) { - ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd); + ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd, true); foreach (ContactResult r in agentHits) results.Add(r); } @@ -14610,7 +14614,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (checkAgents) { - ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd); + ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd, false); foreach (ContactResult r in agentHits) results.Add(r); } From 6956ada5e83d1d1ebcedef6c6154925e8efd501d Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 6 Nov 2016 04:29:01 +0000 Subject: [PATCH 021/305] oops bug fix --- .../Shared/Api/Implementation/LSL_Api.cs | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 33d5757b14..1a73c3e01e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -14519,7 +14519,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Vector3 rayEnd = end; Vector3 dir = rayEnd - rayStart; - float dist = Vector3.Mag(dir); + float dist = dir.Length(); int count = 1; bool detectPhantom = false; @@ -14581,14 +14581,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api object physresults; physresults = World.RayCastFiltered(rayStart, direction, dist, physcount, rayfilter); -/* if (physresults == null) { - list.Add(new LSL_Integer(-3)); // timeout error - return list; +// list.Add(new LSL_Integer(-3)); // timeout error +// return list; + results = new List(); } -*/ - results = (List)physresults; + else + results = (List)physresults; // for now physics doesn't detect sitted avatars so do it outside physics if (checkAgents) @@ -14609,6 +14609,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (ContactResult r in objectHits) results.Add(r); } + // Double check this because of current ODE distance problems + if (checkTerrain && dist > 60) + { + bool skipGroundCheck = false; + + foreach (ContactResult c in results) + { + if (c.ConsumerID == 0) // Physics gave us a ground collision + skipGroundCheck = true; + } + + if (!skipGroundCheck) + { + float tmp = dir.X * dir.X + dir.Y * dir.Y; + if(tmp > 2500) + { + ContactResult? groundContact = GroundIntersection(rayStart, rayEnd); + if (groundContact != null) + results.Add((ContactResult)groundContact); + } + } + } } else { @@ -14629,20 +14651,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api results.Add(objectHits[iter]); } } - } - // Double check this - if (checkTerrain) - { - bool skipGroundCheck = false; - - foreach (ContactResult c in results) - { - if (c.ConsumerID == 0) // Physics gave us a ground collision - skipGroundCheck = true; - } - - if (!skipGroundCheck) + if (checkTerrain) { ContactResult? groundContact = GroundIntersection(rayStart, rayEnd); if (groundContact != null) From d5a428c669c43d4780677556bad5b00e2d40797f Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 7 Nov 2016 11:35:32 +0000 Subject: [PATCH 022/305] add a few more lsl constants for attachments --- .../Shared/Api/Runtime/LSL_Constants.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index bc4d20cc02..cee66b277a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -254,6 +254,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int ATTACH_HUD_BOTTOM_RIGHT = 38; public const int ATTACH_NECK = 39; public const int ATTACH_AVATAR_CENTER = 40; + public const int ATTACH_LHAND_RING1 = 41; + public const int ATTACH_RHAND_RING1 = 42; + public const int ATTACH_TAIL_BASE = 43; + public const int ATTACH_TAIL_TIP = 44; + public const int ATTACH_LWING = 45; + public const int ATTACH_RWING = 46; + public const int ATTACH_FACE_JAW = 47; + public const int ATTACH_FACE_LEAR = 48; + public const int ATTACH_FACE_REAR = 49; + public const int ATTACH_FACE_LEYE = 50; + public const int ATTACH_FACE_REYE = 51; + public const int ATTACH_FACE_TONGUE = 52; + public const int ATTACH_GROIN = 53; + public const int ATTACH_HIND_LFOOT = 54; + public const int ATTACH_HIND_RFOOT = 55; #region osMessageAttachments constants From d0ae8bb86aa64632cf2e3d4e879d7a5f5fb96bb3 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 7 Nov 2016 12:45:20 +0000 Subject: [PATCH 023/305] start removing old hack of using SetMomentum to just set instant velocity, now that TargetVelocity is avaiable --- .../PhysicsModules/ubOde/ODECharacter.cs | 40 ++++++++++++++++--- .../Region/PhysicsModules/ubOde/ODEPrim.cs | 5 ++- .../Region/PhysicsModules/ubOde/ODEScene.cs | 1 + 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs b/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs index 9640e911af..f7e1044622 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs @@ -632,6 +632,25 @@ namespace OpenSim.Region.PhysicsModule.ubOde } } + public override Vector3 TargetVelocity + { + get + { + return m_targetVelocity; + } + set + { + if (value.IsFinite()) + { + AddChange(changes.TargetVelocity, value); + } + else + { + m_log.Warn("[PHYSICS]: Got a NaN velocity from Scene in a Character"); + } + } + } + public override Vector3 Torque { get { return Vector3.Zero; } @@ -689,7 +708,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde } else { - AddChange(changes.Velocity, force); + AddChange(changes.TargetVelocity, force); } } else @@ -1671,16 +1690,14 @@ namespace OpenSim.Region.PhysicsModule.ubOde { AvatarGeomAndBodyDestroy(); - float oldsz = m_size.Z; m_size = pSize; - AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z + (m_size.Z - oldsz) * 0.5f); - Velocity = Vector3.Zero; - +// Velocity = Vector3.Zero; + m_targetVelocity = Vector3.Zero; _parent_scene.actor_name_map[collider] = (PhysicsActor)this; _parent_scene.actor_name_map[capsule] = (PhysicsActor)this; @@ -1738,6 +1755,15 @@ namespace OpenSim.Region.PhysicsModule.ubOde } private void changeVelocity(Vector3 newVel) + { + _velocity = newVel; + setFreeMove(); + + if (Body != IntPtr.Zero) + d.BodySetLinearVel(Body, newVel.X, newVel.Y, newVel.Z); + } + + private void changeTargetVelocity(Vector3 newVel) { m_pidControllerActive = true; m_freemove = false; @@ -1881,6 +1907,10 @@ namespace OpenSim.Region.PhysicsModule.ubOde changeVelocity((Vector3)arg); break; + case changes.TargetVelocity: + changeTargetVelocity((Vector3)arg); + break; + // case changes.Acceleration: // changeacceleration((Vector3)arg); // break; diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs b/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs index 4adf87ef30..3403f4baac 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs @@ -3805,6 +3805,9 @@ namespace OpenSim.Region.PhysicsModule.ubOde changevelocity((Vector3)arg); break; + case changes.TargetVelocity: + break; + // case changes.Acceleration: // changeacceleration((Vector3)arg); // break; @@ -3933,8 +3936,6 @@ namespace OpenSim.Region.PhysicsModule.ubOde donullchange(); break; - - default: donullchange(); break; diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs b/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs index e6aa7ef360..6267051aac 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs @@ -112,6 +112,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde OriOffset, // not in use // arg Vector3 new position in local coords. Changes prim position in object Velocity, + TargetVelocity, AngVelocity, Acceleration, Force, From 07893ec3e7e2bfe2066eb0477574543b4efa6930 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 7 Nov 2016 16:03:23 +0000 Subject: [PATCH 024/305] a few more changes on the avatars Velocity/TargetVelocity/SetMomentum. Need talk with Robert before last changes bc of bullet --- .../Region/Framework/Scenes/ScenePresence.cs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 6f4d6c3f97..f96fb858ec 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -781,6 +781,34 @@ namespace OpenSim.Region.Framework.Scenes } } + // requested Velocity for physics engines avatar motors + // only makes sense if there is a physical rep + public Vector3 TargetVelocity + { + get + { + if (PhysicsActor != null) + return PhysicsActor.TargetVelocity; + else + return Vector3.Zero; + } + + set + { + if (PhysicsActor != null) + { + try + { + PhysicsActor.TargetVelocity = value; + } + catch (Exception e) + { + m_log.Error("[SCENE PRESENCE]: TARGETVELOCITY " + e.Message); + } + } + } + } + private Quaternion m_bodyRot = Quaternion.Identity; /// @@ -3649,7 +3677,7 @@ namespace OpenSim.Region.Framework.Scenes m_forceToApplyValid = true; } */ - Velocity = direc; + TargetVelocity = direc; Animator.UpdateMovementAnimations(); } From 7ebc08ad6512670ed9897c27475e278168eab18d Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 7 Nov 2016 18:34:45 +0000 Subject: [PATCH 025/305] partially revert commit f29d5ad662387b97d9e881f28df584dc19fa8c07: if mesh asset does not contain data for PRIM type warn and use convex, do avoid physical peims going underground etc --- .../ubOdeMeshing/Meshmerizer.cs | 284 +++++++++--------- 1 file changed, 145 insertions(+), 139 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs index bcd1530302..ca94034b10 100644 --- a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs +++ b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs @@ -395,6 +395,10 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing { // m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName); + + // for ubOde we have a diferent mesh use priority + // priority is to use full mesh then decomposition + // SL does the oposite bool usemesh = false; coords = new List(); @@ -443,16 +447,10 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing if (physicsParms != null) usemesh = true; - else - { - m_log.WarnFormat("[MESH]: Data for PRIM shape type not found for prim {0}",primName); - return false; - } } if(!usemesh && (map.ContainsKey("physics_convex"))) physicsParms = (OSDMap)map["physics_convex"]; - if (physicsParms == null) { @@ -555,160 +553,168 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing range = range - min; range *= invMaxU16; - if (!convex && cmap.ContainsKey("HullList") && cmap.ContainsKey("Positions")) + if(!convex) { - List hsizes = new List(); - int totalpoints = 0; - data = cmap["HullList"].AsBinary(); - for (i = 0; i < data.Length; i++) + // if mesh data not present and not convex then we need convex decomposition data + if (cmap.ContainsKey("HullList") && cmap.ContainsKey("Positions")) { - t1 = data[i]; - if (t1 == 0) - t1 = 256; - totalpoints += t1; - hsizes.Add(t1); - } - - data = cmap["Positions"].AsBinary(); - int ptr = 0; - int vertsoffset = 0; - - if (totalpoints == data.Length / 6) // 2 bytes per coord, 3 coords per point - { - foreach (int hullsize in hsizes) + List hsizes = new List(); + int totalpoints = 0; + data = cmap["HullList"].AsBinary(); + for (i = 0; i < data.Length; i++) { - for (i = 0; i < hullsize; i++ ) - { - t1 = data[ptr++]; - t1 += data[ptr++] << 8; - t2 = data[ptr++]; - t2 += data[ptr++] << 8; - t3 = data[ptr++]; - t3 += data[ptr++] << 8; + t1 = data[i]; + if (t1 == 0) + t1 = 256; + totalpoints += t1; + hsizes.Add(t1); + } - f3 = new float3((t1 * range.X + min.X), - (t2 * range.Y + min.Y), - (t3 * range.Z + min.Z)); - vs.Add(f3); - } + data = cmap["Positions"].AsBinary(); + int ptr = 0; + int vertsoffset = 0; - if(hullsize <3) + if (totalpoints == data.Length / 6) // 2 bytes per coord, 3 coords per point + { + foreach (int hullsize in hsizes) { - vs.Clear(); - continue; - } - - if (hullsize <5) - { - foreach (float3 point in vs) + for (i = 0; i < hullsize; i++ ) { - c.X = point.x; - c.Y = point.y; - c.Z = point.z; + t1 = data[ptr++]; + t1 += data[ptr++] << 8; + t2 = data[ptr++]; + t2 += data[ptr++] << 8; + t3 = data[ptr++]; + t3 += data[ptr++] << 8; + + f3 = new float3((t1 * range.X + min.X), + (t2 * range.Y + min.Y), + (t3 * range.Z + min.Z)); + vs.Add(f3); + } + + if(hullsize <3) + { + vs.Clear(); + continue; + } + + if (hullsize <5) + { + foreach (float3 point in vs) + { + c.X = point.x; + c.Y = point.y; + c.Z = point.z; + coords.Add(c); + } + f = new Face(vertsoffset, vertsoffset + 1, vertsoffset + 2); + faces.Add(f); + + if (hullsize == 4) + { + // not sure about orientation.. + f = new Face(vertsoffset, vertsoffset + 2, vertsoffset + 3); + faces.Add(f); + f = new Face(vertsoffset, vertsoffset + 3, vertsoffset + 1); + faces.Add(f); + f = new Face(vertsoffset + 3, vertsoffset + 2, vertsoffset + 1); + faces.Add(f); + } + vertsoffset += vs.Count; + vs.Clear(); + continue; + } + /* + if (!HullUtils.ComputeHull(vs, ref hullr, 0, 0.0f)) + { + vs.Clear(); + continue; + } + + nverts = hullr.Vertices.Count; + nindexs = hullr.Indices.Count; + + if (nindexs % 3 != 0) + { + vs.Clear(); + continue; + } + + for (i = 0; i < nverts; i++) + { + c.X = hullr.Vertices[i].x; + c.Y = hullr.Vertices[i].y; + c.Z = hullr.Vertices[i].z; coords.Add(c); } - f = new Face(vertsoffset, vertsoffset + 1, vertsoffset + 2); - faces.Add(f); - - if (hullsize == 4) + + for (i = 0; i < nindexs; i += 3) { - // not sure about orientation.. - f = new Face(vertsoffset, vertsoffset + 2, vertsoffset + 3); - faces.Add(f); - f = new Face(vertsoffset, vertsoffset + 3, vertsoffset + 1); - faces.Add(f); - f = new Face(vertsoffset + 3, vertsoffset + 2, vertsoffset + 1); + t1 = hullr.Indices[i]; + if (t1 > nverts) + break; + t2 = hullr.Indices[i + 1]; + if (t2 > nverts) + break; + t3 = hullr.Indices[i + 2]; + if (t3 > nverts) + break; + f = new Face(vertsoffset + t1, vertsoffset + t2, vertsoffset + t3); faces.Add(f); } - vertsoffset += vs.Count; - vs.Clear(); - continue; - } -/* - if (!HullUtils.ComputeHull(vs, ref hullr, 0, 0.0f)) - { - vs.Clear(); - continue; - } + */ + List indices; + if (!HullUtils.ComputeHull(vs, out indices)) + { + vs.Clear(); + continue; + } - nverts = hullr.Vertices.Count; - nindexs = hullr.Indices.Count; + nverts = vs.Count; + nindexs = indices.Count; - if (nindexs % 3 != 0) - { - vs.Clear(); - continue; - } + if (nindexs % 3 != 0) + { + vs.Clear(); + continue; + } - for (i = 0; i < nverts; i++) - { - c.X = hullr.Vertices[i].x; - c.Y = hullr.Vertices[i].y; - c.Z = hullr.Vertices[i].z; - coords.Add(c); - } + for (i = 0; i < nverts; i++) + { + c.X = vs[i].x; + c.Y = vs[i].y; + c.Z = vs[i].z; + coords.Add(c); + } - for (i = 0; i < nindexs; i += 3) - { - t1 = hullr.Indices[i]; - if (t1 > nverts) - break; - t2 = hullr.Indices[i + 1]; - if (t2 > nverts) - break; - t3 = hullr.Indices[i + 2]; - if (t3 > nverts) - break; - f = new Face(vertsoffset + t1, vertsoffset + t2, vertsoffset + t3); - faces.Add(f); - } -*/ - List indices; - if (!HullUtils.ComputeHull(vs, out indices)) - { + for (i = 0; i < nindexs; i += 3) + { + t1 = indices[i]; + if (t1 > nverts) + break; + t2 = indices[i + 1]; + if (t2 > nverts) + break; + t3 = indices[i + 2]; + if (t3 > nverts) + break; + f = new Face(vertsoffset + t1, vertsoffset + t2, vertsoffset + t3); + faces.Add(f); + } + vertsoffset += nverts; vs.Clear(); - continue; } - - nverts = vs.Count; - nindexs = indices.Count; - - if (nindexs % 3 != 0) - { - vs.Clear(); - continue; - } - - for (i = 0; i < nverts; i++) - { - c.X = vs[i].x; - c.Y = vs[i].y; - c.Z = vs[i].z; - coords.Add(c); - } - - for (i = 0; i < nindexs; i += 3) - { - t1 = indices[i]; - if (t1 > nverts) - break; - t2 = indices[i + 1]; - if (t2 > nverts) - break; - t3 = indices[i + 2]; - if (t3 > nverts) - break; - f = new Face(vertsoffset + t1, vertsoffset + t2, vertsoffset + t3); - faces.Add(f); - } - vertsoffset += nverts; - vs.Clear(); } + if (coords.Count > 0 && faces.Count > 0) + return true; + } + else + { + // if neither mesh or decomposition present, warn and use convex + m_log.WarnFormat("[MESH]: Data for PRIM shape type ( mesh or decomposition) not found for prim {0}",primName); } - if (coords.Count > 0 && faces.Count > 0) - return true; } - vs.Clear(); if (cmap.ContainsKey("BoundingVerts")) From 6218913345ae22ef5c95fa71ee4f36f46c7a5644 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 8 Nov 2016 11:22:08 +0000 Subject: [PATCH 026/305] add some configuration options missing in OpenSimDeafults.ini but present in OpenSim.ini.example --- bin/OpenSimDefaults.ini | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index c4a01a6ef1..6b04424a87 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -306,12 +306,23 @@ DefaultScriptEngine = "XEngine" + ; Http proxy setting for llHTTPRequest and dynamic texture loading, if + ; required + ; HttpProxy = "http://proxy.com:8080" + + ; If you're using HttpProxy, then you can set HttpProxyExceptions to a + ; list of regular expressions for URLs that you don't want to go through + ; the proxy. + ; For example, servers inside your firewall. + ; Separate patterns with a ';' + ; HttpProxyExceptions = ".mydomain.com;localhost" + ; ## ; ## EMAIL MODULE ; ## ;emailmodule = DefaultEmailModule - + ; ## ; ## ANIMATIONS ; ## @@ -324,6 +335,10 @@ ; won't look right until the physics engine supports it ; (i.e delays takeoff for a moment) + ; # + ; # statistics + ; # + ; Simulator statistics are output to the console periodically at debug level INFO. ; Setting this to zero disables this output. ; LogShowStatsSeconds = 3600 @@ -362,6 +377,23 @@ ; system with reduced logging LogOverloads = True + ; # + ; # Telehubs + ; # + + ; SpawnPointRouting adjusts the landing for incoming avatars. + ; "closest" will place the avatar at the SpawnPoint located in the closest + ; available spot to the destination (typically map click/landmark). + ; "random" will place the avatar on a randomly selected spawnpoint; + ; "sequence" will place the avatar on the next sequential SpawnPoint + ; SpawnPointRouting = closest + + ; TelehubAllowLandmark allows users with landmarks to override telehub + ; routing and land at the landmark coordinates when set to true + ; default is false + ; TelehubAllowLandmark = false + + [Map] ;WorldMapModule = "WorldMap" ;MapImageModule = "MapImageModule" From 6c44dceced81f3ae0a7650f8186f17b15dd55fe0 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 8 Nov 2016 13:39:49 +0000 Subject: [PATCH 027/305] change display and log of normal script errors --- .../Shared/Instance/ScriptInstance.cs | 61 +++++++++++++------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 611df58952..d72590792a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -924,26 +924,53 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance { try { - // DISPLAY ERROR INWORLD - string text = FormatException(e); - if (text.Length > 1000) - text = text.Substring(0, 1000); - Engine.World.SimChat(Utils.StringToBytes(text), - ChatTypeEnum.DebugChannel, 2147483647, - Part.AbsolutePosition, - Part.Name, Part.UUID, false); + if(e.InnerException != null && e.InnerException is ScriptException) + { + string text = e.InnerException.Message + + "(script: " + ScriptName + + " event: " + data.EventName + + " at " + Part.AbsolutePosition + ")"; + if (text.Length > 1000) + text = text.Substring(0, 1000); + Engine.World.SimChat(Utils.StringToBytes(text), + ChatTypeEnum.DebugChannel, 2147483647, + Part.AbsolutePosition, + Part.Name, Part.UUID, false); + m_log.Debug(string.Format( + "[SCRIPT INSTANCE]: {0} (at event {1}, part {2} {3} at {4} in {5}", + e.InnerException.Message, + data.EventName, + PrimName, + Part.UUID, + Part.AbsolutePosition, + Part.ParentGroup.Scene.Name)); + + } + else + { + + // DISPLAY ERROR INWORLD + string text = FormatException(e); + + if (text.Length > 1000) + text = text.Substring(0, 1000); + Engine.World.SimChat(Utils.StringToBytes(text), + ChatTypeEnum.DebugChannel, 2147483647, + Part.AbsolutePosition, + Part.Name, Part.UUID, false); - m_log.Debug(string.Format( - "[SCRIPT INSTANCE]: Runtime error in script {0} (event {1}), part {2} {3} at {4} in {5} ", - ScriptName, - data.EventName, - PrimName, - Part.UUID, - Part.AbsolutePosition, - Part.ParentGroup.Scene.Name), - e); + m_log.Debug(string.Format( + "[SCRIPT INSTANCE]: Runtime error in script {0} (event {1}), part {2} {3} at {4} in {5} ", + ScriptName, + data.EventName, + PrimName, + Part.UUID, + Part.AbsolutePosition, + Part.ParentGroup.Scene.Name), + e); + } } catch (Exception) { From 92984556e1e8b8386b2362b821679ed76891e262 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 8 Nov 2016 23:09:53 +0000 Subject: [PATCH 028/305] change the clock source on tokenBucket --- .../ClientStack/Linden/UDP/TokenBucket.cs | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs index 0ac573ac1b..7b9661b80c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs @@ -62,8 +62,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// protected const float m_minimumDripRate = 1500; - /// Time of the last drip, in system ticks - protected Int32 m_lastDrip; + /// Time of the last drip + protected double m_lastDrip; /// /// The number of bytes that can be sent at this moment. This is the @@ -166,10 +166,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// protected float m_totalDripRequest; public float TotalDripRequest - { - get { return m_totalDripRequest; } - set { m_totalDripRequest = value; } - } + { + get { return m_totalDripRequest; } + set { m_totalDripRequest = value; } + } #endregion Properties @@ -193,9 +193,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP Parent = parent; RequestedDripRate = dripRate; RequestedBurst = MaxBurst; - // TotalDripRequest = dripRate; // this will be overwritten when a child node registers - // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); - m_lastDrip = Util.EnvironmentTickCount() + 100000; + m_lastDrip = Util.GetTimeStampMS() + 50.0; } #endregion Constructor @@ -210,7 +208,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected float DripRateModifier() { float driprate = DripRate; - return driprate >= TotalDripRequest ? 1.0f : driprate / TotalDripRequest; + return driprate >= TotalDripRequest ? 1.0f : (driprate / TotalDripRequest); } /// @@ -313,14 +311,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP return; } - Int32 now = Util.EnvironmentTickCount(); - Int32 deltaMS = now - m_lastDrip; + double now = Util.GetTimeStampMS(); + double deltaMS = now - m_lastDrip; m_lastDrip = now; if (deltaMS <= 0) return; - m_tokenCount += deltaMS * DripRate * m_timeScale; + m_tokenCount += (float)deltaMS * DripRate * m_timeScale; float burst = Burst; if (m_tokenCount > burst) From 94d2422230be405f44be3697e663ef4fac8369f8 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 9 Nov 2016 10:21:02 +0000 Subject: [PATCH 029/305] change the clock source on udp outgoing, remove some dead code --- .../ClientStack/Linden/UDP/LLUDPServer.cs | 134 ++---------------- .../ClientStack/Linden/UDP/ThrottleRates.cs | 4 +- .../Agent/UDP/Linden/LindenUDPInfoModule.cs | 25 ---- 3 files changed, 10 insertions(+), 153 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 0e67095146..8355f2b13c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -323,7 +323,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected int m_elapsedMSSinceLastStatReport = 0; /// Environment.TickCount of the last time the outgoing packet handler executed - protected int m_tickLastOutgoingPacketHandler; + protected double m_tickLastOutgoingPacketHandler; /// Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped protected int m_elapsedMSOutgoingPacketHandler; @@ -356,20 +356,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - - protected ExpiringCache> m_pendingCache = new ExpiringCache>(); - /// - /// Event used to signal when queued packets are available for sending. - /// - /// - /// This allows the outbound loop to only operate when there is data to send rather than continuously polling. - /// Some data is sent immediately and not queued. That data would not trigger this event. - /// WRONG use. May be usefull in future revision - /// -// protected AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); - protected Pool m_incomingPacketPool; /// @@ -467,8 +455,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP int sceneThrottleBps = 0; bool usePools = false; - - IConfig config = configSource.Configs["ClientStack.LindenUDP"]; if (config != null) { @@ -927,10 +913,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } PacketPool.Instance.ReturnPacket(packet); - - /// WRONG use. May be usefull in future revision -// if (packetQueued) -// m_dataPresentEvent.Set(); } /// @@ -2079,14 +2061,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_sendPing = false; // Update elapsed time - int thisTick = Environment.TickCount & Int32.MaxValue; - if (m_tickLastOutgoingPacketHandler > thisTick) - m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick); - else - m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler); - + double thisTick = Util.GetTimeStampMS(); + int deltaMS = (int)(thisTick - m_tickLastOutgoingPacketHandler); m_tickLastOutgoingPacketHandler = thisTick; + // update some 1ms resolution chained timers + + m_elapsedMSOutgoingPacketHandler += deltaMS; + // Check for pending outgoing resends every 100ms if (m_elapsedMSOutgoingPacketHandler >= 100) { @@ -2109,15 +2091,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_sendPing = true; m_elapsed500MSOutgoingPacketHandler = 0; } - #endregion Update Timers - // Use this for emergency monitoring -- bug hunting - //if (m_scene.EmergencyMonitoring) - // clientPacketHandler = MonitoredClientOutgoingPacketHandler; - //else - // clientPacketHandler = ClientOutgoingPacketHandler; - // Handle outgoing packets, resends, acknowledgements, and pings for each // client. m_packetSent will be set to true if a packet is sent Scene.ForEachClient(clientPacketHandler); @@ -2129,7 +2104,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if(Scene.GetNumberOfClients() == 0) { - Thread.Sleep(250); // be friendly to PIs, but how long ?? + Thread.Sleep(100); } else if (!m_packetSent) // Thread.Sleep((int)TickCountResolution); outch this is bad on linux @@ -2204,99 +2179,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public long IncomingPacketsProcessed { get; protected set; } - protected void MonitoredClientOutgoingPacketHandler(IClientAPI client) - { - nticks++; - watch1.Start(); - m_currentOutgoingClient = client; - - try - { - if (client is LLClientView) - { - LLClientView llClient = (LLClientView)client; - LLUDPClient udpClient = llClient.UDPClient; - - if (udpClient.IsConnected) - { - if (m_resendUnacked) - { - nticksUnack++; - watch2.Start(); - - HandleUnacked(llClient); - - watch2.Stop(); - avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack); - watch2.Reset(); - } - - if (m_sendAcks) - { - nticksAck++; - watch2.Start(); - - SendAcks(udpClient); - - watch2.Stop(); - avgSendAcksTicks = (nticksAck - 1) / (float)nticksAck * avgSendAcksTicks + (watch2.ElapsedTicks / (float)nticksAck); - watch2.Reset(); - } - - if (m_sendPing) - { - nticksPing++; - watch2.Start(); - - SendPing(udpClient); - - watch2.Stop(); - avgSendPingTicks = (nticksPing - 1) / (float)nticksPing * avgSendPingTicks + (watch2.ElapsedTicks / (float)nticksPing); - watch2.Reset(); - } - - watch2.Start(); - // Dequeue any outgoing packets that are within the throttle limits - if (udpClient.DequeueOutgoing()) - { - m_packetSent = true; - npacksSent++; - } - else - { - npackNotSent++; - } - - watch2.Stop(); - avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks); - watch2.Reset(); - - } - else - { - m_log.WarnFormat("[LLUDPSERVER]: Client is not connected"); - } - } - } - catch (Exception ex) - { - m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + - " threw an exception: " + ex.Message, ex); - } - watch1.Stop(); - avgProcessingTicks = (nticks - 1) / (float)nticks * avgProcessingTicks + (watch1.ElapsedTicks / (float)nticks); - watch1.Reset(); - - // reuse this -- it's every ~100ms - if (Scene.EmergencyMonitoring && nticks % 100 == 0) - { - m_log.InfoFormat("[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})", - avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent); - npackNotSent = npacksSent = 0; - } - - } - #endregion protected void ProcessInPacket(IncomingPacket incomingPacket) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs index a476b919a5..6278e3686d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs @@ -92,8 +92,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP Asset = throttleConfig.GetInt("asset_default", 10500); Total = Resend + Land + Wind + Cloud + Task + Texture + Asset; - // 3000000 bps default max - ClientMaxRate = throttleConfig.GetInt("client_throttle_max_bps", 375000); + // 5120000 bps default max + ClientMaxRate = throttleConfig.GetInt("client_throttle_max_bps", 640000); if (ClientMaxRate > 1000000) ClientMaxRate = 1000000; // no more than 8Mbps diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs index 08d0fbf5bb..071530b753 100644 --- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs +++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs @@ -125,13 +125,6 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden + " With the 'full' option child agents are also shown.", (mod, cmd) => MainConsole.Instance.Output(GetThrottlesReport(cmd))); - scene.AddCommand( - "Comms", this, "emergency-monitoring", - "emergency-monitoring", - "Go on/off emergency monitoring mode", - "Go on/off emergency monitoring mode", - HandleEmergencyMonitoring); - scene.AddCommand( "Comms", this, "show client stats", "show client stats [first_name last_name]", @@ -197,24 +190,6 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden return report.ToString(); } - protected void HandleEmergencyMonitoring(string module, string[] cmd) - { - bool mode = true; - if (cmd.Length == 1 || (cmd.Length > 1 && cmd[1] == "on")) - { - mode = true; - MainConsole.Instance.Output("Emergency Monitoring ON"); - } - else - { - mode = false; - MainConsole.Instance.Output("Emergency Monitoring OFF"); - } - - foreach (Scene s in m_scenes.Values) - s.EmergencyMonitoring = mode; - } - protected string GetColumnEntry(string entry, int maxLength, int columnPadding) { return string.Format( From c349a1a5e76a97d8b421afedcbb6320e846404ad Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 9 Nov 2016 11:21:46 +0000 Subject: [PATCH 030/305] also log estimated average Util.GetTimeStampMS() resolution --- .../ClientStack/Linden/UDP/LLUDPServer.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 8355f2b13c..ffdb6398a9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -444,10 +444,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP int now = start; while (now == start) now = Environment.TickCount; - TickCountResolution += (float)(now - start) * 0.1f; + TickCountResolution += (float)(now - start); } - TickCountResolution = (float)Math.Ceiling(TickCountResolution); - m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); + m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution * 0.1f + "ms"); + + TickCountResolution = 0f; + for (int i = 0; i < 100; i++) + { + double start = Util.GetTimeStampMS(); + double now = start; + while (now == start) + now = Util.GetTimeStampMS(); + TickCountResolution += (float)((now - start)); + } + + TickCountResolution = (float)Math.Round(TickCountResolution * 0.01f,6,MidpointRounding.AwayFromZero); + m_log.Info("[LLUDPSERVER]: Average Util.GetTimeStampMS resolution: " + TickCountResolution + "ms"); #endregion Environment.TickCount Measurement From 924c5fb55e8e5561c2d9d939b1c5dd77a9d6955a Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 9 Nov 2016 19:41:07 +0000 Subject: [PATCH 031/305] minor cleanup --- .../RemoteUserAccountServiceConnector.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs index eead05d7ae..9140d786f5 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs @@ -144,10 +144,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts return account; account = base.GetUserAccount(scopeID, userID); - lock(m_Cache) - if(account != null) + if(account != null) + { + lock(m_Cache) m_Cache.Cache(userID, account); - + } return account; } @@ -162,9 +163,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts account = base.GetUserAccount(scopeID, firstName, lastName); if (account != null) + { lock(m_Cache) m_Cache.Cache(account.PrincipalID, account); - + } return account; } @@ -195,16 +197,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts List ext = base.GetUserAccounts(scopeID, missing); if(ext != null && ext.Count >0 ) { - accs.AddRange(ext); foreach(UserAccount acc in ext) { if(acc != null) + { + accs.Add(acc); lock(m_Cache) m_Cache.Cache(acc.PrincipalID, acc); + } } } } - return accs; } From 1e1d0d8204181e4dedf438332625941cd56b02c2 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 9 Nov 2016 20:09:49 +0000 Subject: [PATCH 032/305] move UserAccountCache access locking to its methods and not callers. --- .../LocalUserAccountServiceConnector.cs | 18 ++---- .../RemoteUserAccountServiceConnector.cs | 27 +++----- .../UserAccounts/UserAccountCache.cs | 64 +++++++++++-------- 3 files changed, 54 insertions(+), 55 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs index 3127199586..a413a8bff1 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs @@ -154,14 +154,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { bool inCache = false; UserAccount account; - lock(m_Cache) - account = m_Cache.Get(userID, out inCache); + account = m_Cache.Get(userID, out inCache); if (inCache) return account; account = UserAccountService.GetUserAccount(scopeID, userID); - lock(m_Cache) - m_Cache.Cache(userID, account); + m_Cache.Cache(userID, account); return account; } @@ -170,15 +168,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { bool inCache = false; UserAccount account; - lock(m_Cache) - account = m_Cache.Get(firstName + " " + lastName, out inCache); + account = m_Cache.Get(firstName + " " + lastName, out inCache); if (inCache) return account; account = UserAccountService.GetUserAccount(scopeID, firstName, lastName); if (account != null) - lock(m_Cache) - m_Cache.Cache(account.PrincipalID, account); + m_Cache.Cache(account.PrincipalID, account); return account; } @@ -201,8 +197,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { if(UUID.TryParse(id, out uuid)) { - lock(m_Cache) - account = m_Cache.Get(uuid, out inCache); + account = m_Cache.Get(uuid, out inCache); if (inCache) ret.Add(account); else @@ -220,8 +215,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts foreach(UserAccount acc in ext) { if(acc != null) - lock(m_Cache) - m_Cache.Cache(acc.PrincipalID, acc); + m_Cache.Cache(acc.PrincipalID, acc); } } return ret; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs index 9140d786f5..60dd97ad90 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs @@ -128,8 +128,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts // flags, title, etc. And country, don't forget country! private void OnNewClient(IClientAPI client) { - lock(m_Cache) - m_Cache.Remove(client.Name); + m_Cache.Remove(client.Name); } #region Overwritten methods from IUserAccountService @@ -138,17 +137,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { bool inCache = false; UserAccount account; - lock(m_Cache) - account = m_Cache.Get(userID, out inCache); + account = m_Cache.Get(userID, out inCache); if (inCache) return account; account = base.GetUserAccount(scopeID, userID); if(account != null) - { - lock(m_Cache) - m_Cache.Cache(userID, account); - } + m_Cache.Cache(userID, account); + return account; } @@ -156,17 +152,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { bool inCache = false; UserAccount account; - lock(m_Cache) - account = m_Cache.Get(firstName + " " + lastName, out inCache); + account = m_Cache.Get(firstName + " " + lastName, out inCache); if (inCache) return account; account = base.GetUserAccount(scopeID, firstName, lastName); if (account != null) - { - lock(m_Cache) - m_Cache.Cache(account.PrincipalID, account); - } + m_Cache.Cache(account.PrincipalID, account); + return account; } @@ -183,8 +176,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { if(UUID.TryParse(id, out uuid)) { - lock(m_Cache) - account = m_Cache.Get(uuid, out inCache); + account = m_Cache.Get(uuid, out inCache); if (inCache) accs.Add(account); else @@ -202,8 +194,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts if(acc != null) { accs.Add(acc); - lock(m_Cache) - m_Cache.Cache(acc.PrincipalID, acc); + m_Cache.Cache(acc.PrincipalID, acc); } } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs index 53610d95af..97baf8703a 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs @@ -44,6 +44,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts private ExpiringCache m_UUIDCache; private ExpiringCache m_NameCache; + private object accessLock = new object(); public UserAccountCache() { @@ -54,60 +55,73 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts public void Cache(UUID userID, UserAccount account) { // Cache even null accounts - m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS); - if (account != null) - m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_EXPIRATION_SECONDS); + lock(accessLock) + { + m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS); + if (account != null) + m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_EXPIRATION_SECONDS); //m_log.DebugFormat("[USER CACHE]: cached user {0}", userID); + } } public void Invalidate(UUID userID) { - m_UUIDCache.Remove(userID); + lock(accessLock) + m_UUIDCache.Remove(userID); } public UserAccount Get(UUID userID, out bool inCache) { UserAccount account = null; inCache = false; - if (m_UUIDCache.TryGetValue(userID, out account)) + lock(accessLock) { - //m_log.DebugFormat("[USER CACHE]: Account {0} {1} found in cache", account.FirstName, account.LastName); - inCache = true; - return account; + if (m_UUIDCache.TryGetValue(userID, out account)) + { + //m_log.DebugFormat("[USER CACHE]: Account {0} {1} found in cache", account.FirstName, account.LastName); + inCache = true; + return account; + } } - return null; } public UserAccount Get(string name, out bool inCache) { inCache = false; - if (!m_NameCache.Contains(name)) - return null; + lock(accessLock) + { + if (!m_NameCache.Contains(name)) + return null; - UserAccount account = null; - UUID uuid = UUID.Zero; - if (m_NameCache.TryGetValue(name, out uuid)) - if (m_UUIDCache.TryGetValue(uuid, out account)) + UserAccount account = null; + UUID uuid = UUID.Zero; + if (m_NameCache.TryGetValue(name, out uuid)) { - inCache = true; - return account; + if (m_UUIDCache.TryGetValue(uuid, out account)) + { + inCache = true; + return account; + } } - + } return null; } public void Remove(string name) { - if (!m_NameCache.Contains(name)) - return; - - UUID uuid = UUID.Zero; - if (m_NameCache.TryGetValue(name, out uuid)) + lock(accessLock) { - m_NameCache.Remove(name); - m_UUIDCache.Remove(uuid); + if (!m_NameCache.Contains(name)) + return; + + UUID uuid = UUID.Zero; + if (m_NameCache.TryGetValue(name, out uuid)) + { + m_NameCache.Remove(name); + m_UUIDCache.Remove(uuid); + } } } } From 53003db4cf8fe468a4c417db72c0dfd9b6c30404 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 9 Nov 2016 22:12:27 +0000 Subject: [PATCH 033/305] stop warning about integer division cast to float --- OpenSim/Region/Framework/Scenes/Scene.cs | 5 ++--- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 168080fa8e..ca32940cd2 100755 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -67,8 +67,6 @@ namespace OpenSim.Region.Framework.Scenes #region Fields - public bool EmergencyMonitoring = false; - /// /// Show debug information about animations. /// @@ -4606,7 +4604,8 @@ Label_GroupsDone: } // TODO: This check should probably be in QueryAccess(). - ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, RegionInfo.RegionSizeX / 2, RegionInfo.RegionSizeY / 2); + ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, + (float)RegionInfo.RegionSizeX * 0.5f, (float)RegionInfo.RegionSizeY * 0.5f); if (nearestParcel == null) { m_log.InfoFormat( diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 1141f541dd..f5f83caad0 100755 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -246,11 +246,11 @@ namespace OpenSim.Region.Framework.Scenes // try to work around that scale down X and Y acording to region size, so reducing the resolution // // viewers need to scale up - float scaleX = m_parentScene.RegionInfo.RegionSizeX / Constants.RegionSize; + float scaleX = (float)m_parentScene.RegionInfo.RegionSizeX / (float)Constants.RegionSize; if (scaleX == 0) scaleX = 1.0f; scaleX = 1.0f / scaleX; - float scaleY = m_parentScene.RegionInfo.RegionSizeY / Constants.RegionSize; + float scaleY = (float)m_parentScene.RegionInfo.RegionSizeY / (float)Constants.RegionSize; if (scaleY == 0) scaleY = 1.0f; scaleY = 1.0f / scaleY; From d1baa3e0c3b1783a68061980ffd8b9693c5a474a Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 9 Nov 2016 22:39:52 +0000 Subject: [PATCH 034/305] fix some invalid string.format arguments --- .../Remote/GroupsServiceRobustConnector.cs | 2 +- OpenSim/Data/MySQL/MySQLXInventoryData.cs | 9 +- OpenSim/Data/PGSQL/PGSQLXInventoryData.cs | 11 ++- .../Framework/Scenes/Scene.PacketHandlers.cs | 2 +- OpenSim/Region/Framework/Scenes/SceneBase.cs | 2 +- .../Shared/Api/Implementation/LSL_Api.cs | 89 ++++++++++++++++++- .../Connectors/Estate/EstateDataConnector.cs | 2 +- 7 files changed, 108 insertions(+), 9 deletions(-) diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs index 26e844eb57..d79e4fa0f0 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs @@ -286,7 +286,7 @@ namespace OpenSim.Groups string requestingAgentID = request["RequestingAgentID"].ToString(); if (!m_GroupsService.RemoveAgentFromGroup(requestingAgentID, agentID, groupID)) - NullResult(result, string.Format("Insufficient permissions.", agentID)); + NullResult(result, string.Format("Insufficient permissions. {0}", agentID)); else result["RESULT"] = "true"; } diff --git a/OpenSim/Data/MySQL/MySQLXInventoryData.cs b/OpenSim/Data/MySQL/MySQLXInventoryData.cs index c74033eefc..9a0044eb8b 100644 --- a/OpenSim/Data/MySQL/MySQLXInventoryData.cs +++ b/OpenSim/Data/MySQL/MySQLXInventoryData.cs @@ -193,7 +193,9 @@ namespace OpenSim.Data.MySQL { using (MySqlCommand cmd = new MySqlCommand()) { - cmd.CommandText = String.Format("select * from inventoryitems where avatarId = ?uuid and assetType = ?type and flags & 1", m_Realm); +// cmd.CommandText = String.Format("select * from inventoryitems where avatarId = ?uuid and assetType = ?type and flags & 1", m_Realm); + + cmd.CommandText = String.Format("select * from inventoryitems where avatarId = ?uuid and assetType = ?type and flags & 1"); cmd.Parameters.AddWithValue("?uuid", principalID.ToString()); cmd.Parameters.AddWithValue("?type", (int)AssetType.Gesture); @@ -212,7 +214,10 @@ namespace OpenSim.Data.MySQL { cmd.Connection = dbcon; - cmd.CommandText = String.Format("select bit_or(inventoryCurrentPermissions) as inventoryCurrentPermissions from inventoryitems where avatarID = ?PrincipalID and assetID = ?AssetID group by assetID", m_Realm); +// cmd.CommandText = String.Format("select bit_or(inventoryCurrentPermissions) as inventoryCurrentPermissions from inventoryitems where avatarID = ?PrincipalID and assetID = ?AssetID group by assetID", m_Realm); + + cmd.CommandText = String.Format("select bit_or(inventoryCurrentPermissions) as inventoryCurrentPermissions from inventoryitems where avatarID = ?PrincipalID and assetID = ?AssetID group by assetID"); + cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString()); cmd.Parameters.AddWithValue("?AssetID", assetID.ToString()); diff --git a/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs b/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs index a22b882c01..c34a8dce87 100644 --- a/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs +++ b/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs @@ -174,7 +174,9 @@ namespace OpenSim.Data.PGSQL { using (NpgsqlCommand cmd = new NpgsqlCommand()) { - cmd.CommandText = String.Format(@"select * from inventoryitems where ""avatarID"" = :uuid and ""assetType"" = :type and ""flags"" = 1", m_Realm); +// cmd.CommandText = String.Format(@"select * from inventoryitems where ""avatarID"" = :uuid and ""assetType"" = :type and ""flags"" = 1", m_Realm); + + cmd.CommandText = String.Format(@"select * from inventoryitems where ""avatarID"" = :uuid and ""assetType"" = :type and ""flags"" = 1"); UUID princID = UUID.Zero; UUID.TryParse(principalID, out princID); @@ -194,11 +196,18 @@ namespace OpenSim.Data.PGSQL { using (NpgsqlCommand cmd = new NpgsqlCommand()) { +/* cmd.CommandText = String.Format(@"select bit_or(""inventoryCurrentPermissions"") as ""inventoryCurrentPermissions"" from inventoryitems where ""avatarID"" = :PrincipalID and ""assetID"" = :AssetID group by ""assetID"" ", m_Realm); +*/ + cmd.CommandText = String.Format(@"select bit_or(""inventoryCurrentPermissions"") as ""inventoryCurrentPermissions"" + from inventoryitems + where ""avatarID"" = :PrincipalID + and ""assetID"" = :AssetID + group by ""assetID"" "); cmd.Parameters.Add(m_database.CreateParameter("PrincipalID", principalID)); cmd.Parameters.Add(m_database.CreateParameter("AssetID", assetID)); diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index a5abe76376..3f48372db3 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -614,7 +614,7 @@ namespace OpenSim.Region.Framework.Scenes { m_log.Error( string.Format( - "[AGENT INVENTORY]: Error in SendInventoryAsync() for {0} with folder ID {1}. Exception ", e)); + "[AGENT INVENTORY]: Error in SendInventoryAsync() for {0} with folder ID {1}. Exception ", e, folderID)); } Thread.Sleep(20); } diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs index 1de55ec9f6..d40662589c 100644 --- a/OpenSim/Region/Framework/Scenes/SceneBase.cs +++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs @@ -287,7 +287,7 @@ namespace OpenSim.Region.Framework.Scenes } catch (Exception e) { - m_log.Error(string.Format("[SCENE]: SceneBase.cs: Close() - Failed with exception ", e)); + m_log.Error(string.Format("[SCENE]: SceneBase.cs: Close() - Failed with exception {0}", e)); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 1a73c3e01e..bafee28fb3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -14358,6 +14358,91 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return contacts.ToArray(); } + private ContactResult? GroundIntersection2(Vector3 rayStart, Vector3 rayEnd) + { + // get work copies + float sx = rayStart.X; + float ex = rayEnd.X; + float sy = rayStart.Y; + float ey = rayEnd.Y; + + float dx = ex - sx; + float dy = ey - sy; + + // region size info + float rsx = World.RegionInfo.RegionSizeX; + + float tmp; + + // region bounds + if(sx < 0) + { + if(ex < 0) // totally outside + return null; + if(dx <= 0) // out and going away + return null; + else if(ex >= rsx) + ex = rsx - 0.001f; + tmp = -sx / dx; + sy += dy * dx; + sx = 0; + } + else if(sx >= rsx) + { + if(ex >= rsx) // totally outside + return null; + if(dx >= 0) // out and going away + return null; + else if(ex < 0) + ex = 0; + tmp = (rsx - sx) / dx; + sy += dy * dx; + sx = rsx - 0.001f; + } + + float rsy = World.RegionInfo.RegionSizeY; + if(sy < 0) + { + if(dy <= 0) // out and going away + return null; + else if(ey >= rsy) + ey = rsy - 0.001f; + tmp = -sy / dy; + sx += dy * dx; + sy = 0; + } + else if(sy >= rsy) + { + if(dy >= 0) // out and going away + return null; + else if(ey < 0) + ey = 0; + tmp = (rsy - sy) / dy; + sx += dy * dx; + sy = rsy - 0.001f; + } + + if(sx < 0 || sx >= rsx) + return null; + + float sz = rayStart.Z; + float ez = rayEnd.Z; + float dz = ez - sz; + + float dist = dx * dx + dy * dy + dz * dz; + if(dist < 0.001) + return null; + dist = (float)Math.Sqrt(dist); + tmp = 1.0f / dist; + Vector3 rayn = new Vector3(dx * tmp, dy * tmp, dz * tmp); + + ContactResult? result = null; + + + + return result; + } + private ContactResult? GroundIntersection(Vector3 rayStart, Vector3 rayEnd) { double[,] heightfield = World.Heightmap.GetDoubles(); @@ -16024,8 +16109,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api catch (InvalidCastException e) { Error(originFunc,string.Format( - " error running rule #{1}: arg #{2} ", - rulesParsed, idx - idxStart) + e.Message); + " error running rule #{0}: arg #{1} {2}", + rulesParsed, idx - idxStart, e.Message)); } finally { diff --git a/OpenSim/Services/Connectors/Estate/EstateDataConnector.cs b/OpenSim/Services/Connectors/Estate/EstateDataConnector.cs index 74935f37df..b9a628160c 100644 --- a/OpenSim/Services/Connectors/Estate/EstateDataConnector.cs +++ b/OpenSim/Services/Connectors/Estate/EstateDataConnector.cs @@ -323,7 +323,7 @@ namespace OpenSim.Services.Connectors } else m_log.Error(string.Format( - "[ESTATE CONNECTOR]: WebException for {0} {1} {2} ", + "[ESTATE CONNECTOR]: WebException for {0} {1} {2} {3}", verb, uri, formdata, e)); } } From bddaef51220198c3a3894edeece750e29337a558 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 10 Nov 2016 17:56:51 +0000 Subject: [PATCH 035/305] on Select use again the priority queues to send ObjectProperties, including physics via caps. This is need to reduce useless redudance --- .../ClientStack/Linden/UDP/LLClientView.cs | 33 ++++++++++++++- .../Framework/Scenes/Scene.PacketHandlers.cs | 42 ++----------------- 2 files changed, 34 insertions(+), 41 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 276b36724d..99c9049e01 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -2856,6 +2856,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendSelectedPartsProprieties(List parts) { +/* not in use // udp part ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); @@ -2893,6 +2894,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP llsdBody.Add("ObjectData", array); eq.Enqueue(BuildEvent("ObjectPhysicsProperties", llsdBody),AgentId); +*/ } @@ -4839,7 +4841,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.Lazy> propertyUpdates = new OpenSim.Framework.Lazy>(); - + + List needPhysics = new List(); + EntityUpdate iupdate; Int32 timeinqueue; // this is just debugging code & can be dropped later @@ -4867,6 +4871,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (update.Entity is SceneObjectPart) { SceneObjectPart sop = (SceneObjectPart)update.Entity; + needPhysics.Add(sop); ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); objectPropertiesBlocks.Value.Add(objPropDB); propertyUpdates.Value.Add(update); @@ -4932,7 +4937,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP // fpcnt++; // fbcnt++; } - + } + + if(needPhysics.Count > 0) + { + IEventQueue eq = Scene.RequestModuleInterface(); + if(eq != null) + { + OSDArray array = new OSDArray(); + foreach(SceneObjectPart sop in needPhysics) + { + OSDMap physinfo = new OSDMap(6); + physinfo["LocalID"] = sop.LocalId; + physinfo["Density"] = sop.Density; + physinfo["Friction"] = sop.Friction; + physinfo["GravityMultiplier"] = sop.GravityModifier; + physinfo["Restitution"] = sop.Restitution; + physinfo["PhysicsShapeType"] = (int)sop.PhysicsShapeType; + array.Add(physinfo); + } + + OSDMap llsdBody = new OSDMap(1); + llsdBody.Add("ObjectData", array); + + eq.Enqueue(BuildEvent("ObjectPhysicsProperties", llsdBody),AgentId); + } } // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index 3f48372db3..24a2db792b 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -166,8 +166,6 @@ namespace OpenSim.Region.Framework.Scenes /// public void SelectPrim(List primIDs, IClientAPI remoteClient) { - List needUpdates = new List(); - foreach(uint primLocalID in primIDs) { SceneObjectPart part = GetSceneObjectPart(primLocalID); @@ -179,8 +177,6 @@ namespace OpenSim.Region.Framework.Scenes if (sog == null) continue; - needUpdates.Add((ISceneEntity)part); - // waste of time because properties do not send prim flags as they should // if a friend got or lost edit rights after login, a full update is needed if(sog.OwnerID != remoteClient.AgentId) @@ -193,10 +189,9 @@ namespace OpenSim.Region.Framework.Scenes part.IsSelected = true; EventManager.TriggerParcelPrimCountTainted(); } - } - if(needUpdates.Count > 0) - remoteClient.SendSelectedPartsProprieties(needUpdates); + part.SendPropertiesToClient(remoteClient); + } } /// @@ -248,38 +243,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart part = GetSceneObjectPart(primLocalID); if (part == null) return; - /* - // A deselect packet contains all the local prims being deselected. However, since selection is still - // group based we only want the root prim to trigger a full update - otherwise on objects with many prims - // we end up sending many duplicate ObjectUpdates - if (part.ParentGroup.RootPart.LocalId != part.LocalId) - return; - - // This is wrong, wrong, wrong. Selection should not be - // handled by group, but by prim. Legacy cruft. - // TODO: Make selection flagging per prim! - // - if (Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId) - || Permissions.CanMoveObject(part.ParentGroup.UUID, remoteClient.AgentId)) - part.ParentGroup.IsSelected = false; - - part.ParentGroup.ScheduleGroupForFullUpdate(); - - // If it's not an attachment, and we are allowed to move it, - // then we might have done so. If we moved across a parcel - // boundary, we will need to recount prims on the parcels. - // For attachments, that makes no sense. - // - if (!part.ParentGroup.IsAttachment) - { - if (Permissions.CanEditObject( - part.UUID, remoteClient.AgentId) - || Permissions.CanMoveObject( - part.UUID, remoteClient.AgentId)) - EventManager.TriggerParcelPrimCountTainted(); - } - */ - + bool oldgprSelect = part.ParentGroup.IsSelected; // This is wrong, wrong, wrong. Selection should not be From 743a9d617e92f2ccd01816aec3bef73df22ed534 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 10 Nov 2016 19:21:07 +0000 Subject: [PATCH 036/305] also cache not found useraccounts when search by ID. Change the expire time to 5minutes in this case --- .../UserAccounts/LocalUserAccountServiceConnector.cs | 5 +---- .../UserAccounts/RemoteUserAccountServiceConnector.cs | 10 +++------- .../UserAccounts/UserAccountCache.cs | 9 +++++++-- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs index a413a8bff1..9325de9854 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs @@ -213,10 +213,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { ret.AddRange(ext); foreach(UserAccount acc in ext) - { - if(acc != null) - m_Cache.Cache(acc.PrincipalID, acc); - } + m_Cache.Cache(acc.PrincipalID, acc); } return ret; } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs index 60dd97ad90..e84b66630f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs @@ -142,8 +142,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts return account; account = base.GetUserAccount(scopeID, userID); - if(account != null) - m_Cache.Cache(userID, account); + m_Cache.Cache(userID, account); return account; } @@ -191,11 +190,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { foreach(UserAccount acc in ext) { - if(acc != null) - { - accs.Add(acc); - m_Cache.Cache(acc.PrincipalID, acc); - } + accs.Add(acc); + m_Cache.Cache(acc.PrincipalID, acc); } } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs index 97baf8703a..f514bd77d4 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs @@ -37,6 +37,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts public class UserAccountCache : IUserAccountCacheModule { private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours! + private const double CACHENULL_EXPIRATION_SECONDS = 600; // 5minutes // private static readonly ILog m_log = // LogManager.GetLogger( @@ -57,9 +58,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts // Cache even null accounts lock(accessLock) { - m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS); - if (account != null) + if (account == null) + m_UUIDCache.AddOrUpdate(userID, null, CACHENULL_EXPIRATION_SECONDS); + else + { + m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS); m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_EXPIRATION_SECONDS); + } //m_log.DebugFormat("[USER CACHE]: cached user {0}", userID); } From 58b7be48a9466ee8df670e743bfa1711fe6a6450 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 10 Nov 2016 23:07:57 +0000 Subject: [PATCH 037/305] ubOde: add a needed lock --- OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs b/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs index 6267051aac..f6426998d3 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs @@ -1221,8 +1221,11 @@ namespace OpenSim.Region.PhysicsModule.ubOde /// public void RemoveCollisionEventReporting(PhysicsActor obj) { - if (_collisionEventPrim.Contains(obj) && !_collisionEventPrimRemove.Contains(obj)) - _collisionEventPrimRemove.Add(obj); + lock(_collisionEventPrimRemove) + { + if (_collisionEventPrim.Contains(obj) && !_collisionEventPrimRemove.Contains(obj)) + _collisionEventPrimRemove.Add(obj); + } } public override float TimeDilation @@ -1759,10 +1762,13 @@ namespace OpenSim.Region.PhysicsModule.ubOde prm.SleeperAddCollisionEvents(); sleepers.Clear(); - foreach (PhysicsActor obj in _collisionEventPrimRemove) - _collisionEventPrim.Remove(obj); + lock(_collisionEventPrimRemove) + { + foreach (PhysicsActor obj in _collisionEventPrimRemove) + _collisionEventPrim.Remove(obj); - _collisionEventPrimRemove.Clear(); + _collisionEventPrimRemove.Clear(); + } // do a ode simulation step d.WorldQuickStep(world, ODE_STEPSIZE); From 56a79a252c285c68cbdc856dc215d1155dff8c36 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 10 Nov 2016 23:14:08 +0000 Subject: [PATCH 038/305] GetUserAccounts cannot cache null accounts --- .../UserAccounts/LocalUserAccountServiceConnector.cs | 9 +++++++-- .../UserAccounts/RemoteUserAccountServiceConnector.cs | 7 +++++-- .../UserAccounts/UserAccountCache.cs | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs index 9325de9854..b72ffbba4a 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs @@ -211,9 +211,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts List ext = UserAccountService.GetUserAccounts(scopeID, missing); if(ext != null && ext.Count > 0) { - ret.AddRange(ext); foreach(UserAccount acc in ext) - m_Cache.Cache(acc.PrincipalID, acc); + { + if(acc != null) + { + ret.Add(acc); + m_Cache.Cache(acc.PrincipalID, acc); + } + } } return ret; } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs index e84b66630f..f5eda11487 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs @@ -190,8 +190,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { foreach(UserAccount acc in ext) { - accs.Add(acc); - m_Cache.Cache(acc.PrincipalID, acc); + if(acc != null) + { + accs.Add(acc); + m_Cache.Cache(acc.PrincipalID, acc); + } } } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs index f514bd77d4..03cb680a0a 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs @@ -37,7 +37,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts public class UserAccountCache : IUserAccountCacheModule { private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours! - private const double CACHENULL_EXPIRATION_SECONDS = 600; // 5minutes + private const double CACHENULL_EXPIRATION_SECONDS = 600; // 10minutes // private static readonly ILog m_log = // LogManager.GetLogger( From 326821f66ed6286ee8b2ea6f5606d3eb902489fc Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 11 Nov 2016 12:59:43 +0000 Subject: [PATCH 039/305] reduce useraccouts cache time --- .../UserAccounts/UserAccountCache.cs | 6 +-- .../PasswordAuthenticationService.cs | 53 +------------------ 2 files changed, 5 insertions(+), 54 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs index 03cb680a0a..6c1cc525b2 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs @@ -36,8 +36,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { public class UserAccountCache : IUserAccountCacheModule { - private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours! - private const double CACHENULL_EXPIRATION_SECONDS = 600; // 10minutes + private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour! + private const double CACHE_NULL_EXPIRATION_SECONDS = 600; // 10minutes // private static readonly ILog m_log = // LogManager.GetLogger( @@ -59,7 +59,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts lock(accessLock) { if (account == null) - m_UUIDCache.AddOrUpdate(userID, null, CACHENULL_EXPIRATION_SECONDS); + m_UUIDCache.AddOrUpdate(userID, null, CACHE_NULL_EXPIRATION_SECONDS); else { m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS); diff --git a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs index a9359f3cd0..2e8ffe5aae 100644 --- a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs +++ b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs @@ -72,11 +72,8 @@ namespace OpenSim.Services.AuthenticationService { realID = UUID.Zero; - m_log.DebugFormat("[AUTH SERVICE]: Authenticating for {0}, user account service present: {1}", principalID, m_UserAccountService != null); + m_log.DebugFormat("[AUTH SERVICE]: Authenticating for {0}", principalID); AuthenticationData data = m_Database.Get(principalID); - UserAccount user = null; - if (m_UserAccountService != null) - user = m_UserAccountService.GetUserAccount(UUID.Zero, principalID); if (data == null || data.Data == null) { @@ -100,53 +97,7 @@ namespace OpenSim.Services.AuthenticationService return GetToken(principalID, lifetime); } - if (user == null) - { - m_log.DebugFormat("[PASS AUTH]: No user record for {0}", principalID); - return String.Empty; - } - - int impersonateFlag = 1 << 6; - - if ((user.UserFlags & impersonateFlag) == 0) - return String.Empty; - - m_log.DebugFormat("[PASS AUTH]: Attempting impersonation"); - - List accounts = m_UserAccountService.GetUserAccountsWhere(UUID.Zero, "UserLevel >= 200"); - if (accounts == null || accounts.Count == 0) - return String.Empty; - - foreach (UserAccount a in accounts) - { - data = m_Database.Get(a.PrincipalID); - if (data == null || data.Data == null || - !data.Data.ContainsKey("passwordHash") || - !data.Data.ContainsKey("passwordSalt")) - { - continue; - } - -// m_log.DebugFormat("[PASS AUTH]: Trying {0}", data.PrincipalID); - - hashed = Util.Md5Hash(password + ":" + - data.Data["passwordSalt"].ToString()); - - if (data.Data["passwordHash"].ToString() == hashed) - { - m_log.DebugFormat("[PASS AUTH]: {0} {1} impersonating {2}, proceeding with login", a.FirstName, a.LastName, principalID); - realID = a.PrincipalID; - return GetToken(principalID, lifetime); - } -// else -// { -// m_log.DebugFormat( -// "[AUTH SERVICE]: Salted hash {0} of given password did not match salted hash of {1} for PrincipalID {2}. Authentication failure.", -// hashed, data.Data["passwordHash"], data.PrincipalID); -// } - } - - m_log.DebugFormat("[PASS AUTH]: Impersonation of {0} failed", principalID); + m_log.DebugFormat("[AUTH SERVICE]: Authenticating FAIL for {0} ", principalID); return String.Empty; } } From c5d85b5465e6c2d6de2836b739324b634f57cc86 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 11 Nov 2016 16:04:20 +0000 Subject: [PATCH 040/305] reduce diferencs btw OpenSimDefaults.ini and OpenSim.ini.example --- bin/OpenSim.ini.example | 10 +++--- bin/OpenSimDefaults.ini | 69 +++++++++++++++++++++++++++++------------ 2 files changed, 54 insertions(+), 25 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 961c141362..f6466b566d 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -696,12 +696,6 @@ ;; then you might want to try setting this to false. ; mesh_sculpted_prim = true - ;# {use_NINJA_physics_joints} {[Startup]physics:OpenDynamicsEngine} {Use jointed (NINJA) physics?} {true false} false - ;; If you would like physics joints to be enabled through a special naming - ;; convention in the client, set this to true. - ;; (see NINJA Physics, http://opensimulator.org/wiki/NINJA_Physics) - ; use_NINJA_physics_joints = false - [RemoteAdmin] ;; This is the remote admin module, which uses XMLRPC requests to ;; manage regions from a web interface. @@ -1138,15 +1132,19 @@ ;; several options to control NPCs creation + ;# {AllowNotOwned} {} {allow NPCs to be created not Owned} {true false} false ;; allow NPCs to be created not Owned {true false} default: true ; AllowNotOwned = false + ;# {AllowSenseAsAvatar} {} {allow NPCs to set to be sensed as Avatars} {true false} false ;; allow NPCs to set to be sensed as Avatars {true false} default: true ; AllowSenseAsAvatar = false + ;# {AllowCloneOtherAvatars} {} {allow NPCs to created cloning any avatar in region} {true false} false ;; allow NPCs to created cloning any avatar in region {true false} default: true ; AllowCloneOtherAvatars = false + ;# {NoNPCGroup} {} {if true NPCs will have no group title, if false display "- NPC -"} {true false} false ;; if true NPCs will have no group title, if false display "- NPC -" for easy identification {true false} default: true ; NoNPCGroup = false diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 6b04424a87..906c7bc143 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -128,9 +128,16 @@ ; Increasing this number will increase memory usage. MaxPrimUndos = 20 + ; Minimum size for non-physical prims.This can be overridden in the region config file (as + ; NonPhysicalPrimMin!). + ; NonPhysicalPrimMin = 0.001 + ; Maximum size of non physical prims. Affects resizing of existing prims. This can be overridden in the region config file (as NonPhysicalPrimMax!). NonPhysicalPrimMax = 256 + ; Minimum size where a prim can be physical. This can be overridden in the region config file. + ; PhysicalPrimMin = 0.01 + ; Maximum size of physical prims. Affects resizing of existing prims. This can be overridden in the region config file. PhysicalPrimMax = 64 @@ -304,6 +311,7 @@ ; ## SCRIPT ENGINE ; ## + ;; Default script engine to use. Currently, we only have XEngine DefaultScriptEngine = "XEngine" ; Http proxy setting for llHTTPRequest and dynamic texture loading, if @@ -320,7 +328,8 @@ ; ## ; ## EMAIL MODULE ; ## - + ;; The email module requires some configuration. It needs an SMTP + ;; server to send mail through. ;emailmodule = DefaultEmailModule ; ## @@ -395,15 +404,23 @@ [Map] + ; Map tile options. + ; If true, then maptiles are generated using the MapImageModule below. + ; If false then the texture referenced by MaptileStaticUUID is used instead, which can also be overridden + ; in individual region config file(s). If you do not want to upload map tiles at all, then you will need + ; both to set this to false and comment out the [Modules] MapImageServiceModule setting in config-include/ + ;GenerateMaptiles = true + ;WorldMapModule = "WorldMap" + + ; The module to use in order to generate map images. + ; MapImageModule is the default. Warp3DImageModule is an alternative experimental module that can + ; generate better images. ;MapImageModule = "MapImageModule" ; World map blacklist timeout in seconds ;BlacklistTimeout = 600 - ; Set to false to not generate any maptiles - ;GenerateMaptiles = true - ; Refresh (in seconds) the map tile periodically ;MaptileRefresh = 0 @@ -431,6 +448,8 @@ ; ## PERMISSIONS ; ## + ; Permission modules to use, separated by comma. + ; Possible modules are DefaultPermissionsModule, PrimLimitsModule ;permissionmodules = "DefaultPermissionsModule" ; If set to false, then, in theory, the server never carries out permission checks (allowing anybody to copy @@ -439,12 +458,22 @@ ; Default is true serverside_object_permissions = true - allow_grid_gods = false - - ; This allows somne control over permissions + + ; This allows some control over permissions ; please note that this still doesn't duplicate SL, and is not intended to + + ; This allows grid users with a UserLevel of 200 or more to assume god + ; powers in the regions in this simulator. + allow_grid_gods = false + + ; Allow region owners to assume god powers in their regions ;region_owner_is_god = true + + ; Allow region managers to assume god powers in regions they manage ;region_manager_is_god = false + + ; Allow parcel owners to assume god powers in their parcels + ; you really may not want this... ;parcel_owner_is_god = false ; Control user types that are allowed to create new scripts @@ -1107,16 +1136,6 @@ ; number^2 physical level of detail of the sculpt texture. 16x16 - 256 verticies mesh_physical_lod = 16 - ; ## - ; ## Joint support - ; ## - - ; If you would like physics joints to be enabled through a special naming - ; convention in the client, set this to true. - ; (See NINJA Physics documentation, http://opensimulator.org/wiki/NINJA_Physics) - ; Default is false - ;use_NINJA_physics_joints = true - ; ## ; ## additional meshing options ; ## @@ -1126,7 +1145,7 @@ ; If you would rather have mesh proxies for simple prims, you can set this to ; true. Note that this will increase memory usage and region startup time. ; Default is false. - ;force_simple_prim_meshing = true + ;force_simple_prim_meshing = false [BulletSim] @@ -2104,7 +2123,19 @@ [NPC] ;; Enable Non Player Character (NPC) facilities Enabled = false - + ;; several options to control NPCs creation + + ;; allow NPCs to be created not Owned {true false} default: true + ; AllowNotOwned = false + + ;; allow NPCs to set to be sensed as Avatars {true false} default: true + ; AllowSenseAsAvatar = false + + ;; allow NPCs to created cloning any avatar in region {true false} default: true + ; AllowCloneOtherAvatars = false + + ;; if true NPCs will have no group title, if false display "- NPC -" for easy identification {true false} default: true + ; NoNPCGroup = false [Terrain] ; Values can be "pinhead-island" or "flat" From 077cfdf698b2f769f3e136a779e1b1e108d1b8ed Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Fri, 11 Nov 2016 22:05:48 +0000 Subject: [PATCH 041/305] Update gitignore to include VS user config folder and remove old FxCop file which is not used --- .gitignore | 2 +- OpenSim.FxCop | 7241 ------------------------------------------------- 2 files changed, 1 insertion(+), 7242 deletions(-) delete mode 100644 OpenSim.FxCop diff --git a/.gitignore b/.gitignore index d1f7710f47..f77d9f9079 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ */*/*/*/*/bin */*/*/*/*/*/bin */*/*/*/*/*/*/bin +.vs/ addon-modules/ bin/Debug/*.dll bin/*.dll.mdb @@ -93,7 +94,6 @@ TAGS Makefile.local bin/.version compile.bat -addon-modules OpenSim/Data/Tests/test-results/ OpenSim/Framework/Serialization/Tests/test-results/ OpenSim/Framework/Servers/Tests/test-results/ diff --git a/OpenSim.FxCop b/OpenSim.FxCop deleted file mode 100644 index d07c26efbf..0000000000 --- a/OpenSim.FxCop +++ /dev/null @@ -1,7241 +0,0 @@ - - - - True - http://www.gotdotnet.com/team/fxcop//xsl/1.35/FxCopReport.xsl - - - - - - True - True - True - 10 - 1 - - False - False - - False - 120 - - - - $(ProjectDir)/lib/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Sim - OpenSim - - - - - - - - - Sim - OpenSim.Assets - - - - - - - - - OpenSim.CAPS - - - - - Sim - OpenSim.CAPS - - - - - OpenSim.CAPS - - - - - - - - - Sim - OpenSim.Config.SimConfigDb4o - - - Sim - OpenSim.Config.SimConfigDb4o - - - - - - - - - OpenSim.Framework.Assets - - - - - Sim - OpenSim.Framework.Assets - - - - - - - - - Sim - OpenSim.Framework.Console - - - - - - - - - OpenSim.Framework.Grid - - - - - Sim - OpenSim.Framework.Grid - - - - - - - - - Sim - OpenSim.Framework.Interfaces - - - - - - - - - OpenSim.Framework.Inventory - - - - - Sim - OpenSim.Framework.Inventory - - - - - - - - - OpenSim.Framework.Sims - - - - - Sim - OpenSim.Framework.Sims - - - - - - - - - OpenSim.Framework.Terrain - - - - - Sim - OpenSim.Framework.Terrain - - - - - - - - - OpenSim.Framework.User - - - - - Sim - OpenSim.Framework.User - - - - - - - - - OpenSim.Framework.Utilities - - - - - Sim - OpenSim.Framework.Utilities - - - - - - - - - Sim - OpenSim.GridInterfaces.Local - - - - - - - - - OpenSim.GridInterfaces.Remote - - - - - Sim - OpenSim.GridInterfaces.Remote - - - - - - - - - Plugin - OpenSim.Physics.BasicPhysicsPlugin - - - - - Sim - OpenSim.Physics.BasicPhysicsPlugin - - - - - - - - - Sim - OpenSim.Physics.Manager - - - - - - - - - OpenSim.Physics.OdePlugin - - - - - Plugin - OpenSim.Physics.OdePlugin - - - - - Sim - OpenSim.Physics.OdePlugin - - - - - - - - - OpenSim.Physics.PhysXPlugin - - - - - Plugin - OpenSim.Physics.PhysXPlugin - - - - - Sim - OpenSim.Physics.PhysXPlugin - - - - - - - - - Sim - OpenSim.Storage.LocalStorageDb4o - - - - - - - - - OpenSim.types - - - - - OpenSim.types - - - - - Sim - OpenSim.types - - - - - - - - - OpenSim.UserServer - - - - - Sim - OpenSim.UserServer - - - - - - - - - OpenSim.world - - - - - Sim - OpenSim.world - - - - - - - - - OpenSim.world.scripting - - - - - OpenSim.world.scripting - - - OpenSim.world.scripting - - - - - Sim - OpenSim.world.scripting - - - - - - - - - - - - - OpenGridServices.ServerConsole - - - - - OpenGridServices.ServerConsole - - - - - OpenGridServices.ServerConsole - - - - - - - - - - - conscmd_callback - - - - - conscmd - ServerConsole.conscmd_callback - - - - - conscmd_callback - - - - - - - - - conscmd_callback.RunCmd(String, String[]):Void - cmdparams - cmdparams - - - - - - - - - ShowWhat - - - - - - - - - - - - - ConsoleBase.CmdPrompt(String, String):String - defaultresponse - defaultresponse - - - - - - - - - OptionA - - - - - OptionB - - - - - ConsoleBase.CmdPrompt(String, String, String, String):String - defaultresponse - defaultresponse - - - - - - - - - Passwd - ConsoleBase.PasswdPrompt(String):String - - - - - - - - - Cmd - - - - - ConsoleBase.RunCmd(String, String[]):Object - cmdparams - cmdparams - - - - - - - - - ShowWhat - - - - - - - - - Line - - - - - - - - - Line - - - - - - - - - - - - - Sim - ConsoleType.SimChat - - - - - - - - - ConsoleType.TCP - - - - - - - - - - - MainConsole - - - - - - - - - - - - - - - - - OpenSim.Config.SimConfigDb4o - - - - - OpenSim.Config.SimConfigDb4o - - - - - OpenSim.Config.SimConfigDb4o - - - - - - - - - - - Plugin - OpenSim.Config.SimConfigDb4o.Db40ConfigPlugin - - - - - - - - - Sim - OpenSim.Config.SimConfigDb4o.DbSimConfig - - - - - Db - OpenSim.Config.SimConfigDb4o.DbSimConfig - - - - - - - - - DbSimConfig.InitConfig(Boolean):Void - System.Exception - - - - - DbSimConfig.InitConfig(Boolean):Void - System.UInt32.ToString - System.UInt32.ToString(System.IFormatProvider) - - - - - DbSimConfig.InitConfig(Boolean):Void - System.UInt64.ToString - System.UInt64.ToString(System.IFormatProvider) - - - - - - - - - DbSimConfig.LoadDefaults():Void - System.Convert.ToInt32(System.String) - System.Convert.ToInt32(System.String,System.IFormatProvider) - - - DbSimConfig.LoadDefaults():Void - System.Convert.ToInt32(System.String) - System.Convert.ToInt32(System.String,System.IFormatProvider) - - - DbSimConfig.LoadDefaults():Void - System.Convert.ToInt32(System.String) - System.Convert.ToInt32(System.String,System.IFormatProvider) - - - - - - - - - - - - - Map - - - - - - - - - - - - - - - - - - - OpenSim - - - - - OpenSim - - - - - OpenSim - - - - - OpenSim - - - - - OpenSim - - - - - - - - - - - - - 'args' - RegionServer.Main(String[]):Void - - - 'args' - RegionServer.Main(String[]):Void - - - - - - - - - - - - - - - - - - - OpenSim.Framework.Console - - - - - OpenSim.Framework.Console - - - - - OpenSim.Framework.Console - - - - - - - - - - - - - ConsoleBase.CmdPrompt(String, String):String - defaultresponse - defaultresponse - - - - - - - - - OptionA - - - - - OptionB - - - - - ConsoleBase.CmdPrompt(String, String, String, String):String - defaultresponse - defaultresponse - - - - - - - - - Cmd - - - - - ConsoleBase.RunCmd(String, String[]):Object - cmdparams - cmdparams - - - - - - - - - ShowWhat - - - - - - - - - - - - - Sim - ConsoleType.SimChat - - - - - - - - - ConsoleType.TCP - - - - - - - - - - - MainConsole - - - - - - - - - - - - - - - - - OpenSim.Framework - - - - - OpenSim.Framework - - - - - OpenSim.Framework - - - - - - - - - - - - - Data - - - - - - - - - Description - - - - - - - - - FullID - - - - - - - - - InvType - - - - - - - - - Name - - - - - - - - - Type - - - - - - - - - - - - - PrimData.PrimData() - ParentID - System.UInt32 - 0 - - - - - - - - - FullID - - - - - - - - - LocalID - - - - - - - - - OwnerID - - - - - - - - - ParentID - - - - - - - - - PathBegin - - - - - - - - - PathCurve - - - - - - - - - PathEnd - - - - - - - - - PathRadiusOffset - - - - - - - - - PathRevolutions - - - - - - - - - PathScaleX - - - - - - - - - PathScaleY - - - - - - - - - PathShearX - - - - - - - - - PathShearY - - - - - - - - - PathSkew - - - - - - - - - PathTaperX - - - - - - - - - PathTaperY - - - - - - - - - PathTwist - - - - - - - - - PathTwistBegin - - - - - - - - - PCode - - - - - - - - - Position - - - - - - - - - ProfileBegin - - - - - - - - - ProfileCurve - - - - - - - - - ProfileEnd - - - - - - - - - ProfileHollow - - - - - - - - - Rotation - - - - - - - - - Scale - - - - - - - - - Texture - - - - - - - - - - - - - - - Login - LoginService - LogOn - - - - - - - - - - - - - - - AgentID - - - - - - - - - circuitcode - - - - - circuitcode - AgentCircuitData.circuitcode - - - - - - - - - firstname - - - - - firstname - AgentCircuitData.firstname - - - - - - - - - lastname - - - - - lastname - AgentCircuitData.lastname - - - - - - - - - SecureSessionID - - - - - - - - - SessionID - - - - - - - - - - - OpenSim.Framework.Interfaces.ARequest - - - OpenSim.Framework.Interfaces.ARequest - - - - - - - - - AssetID - - - - - - - - - IsTexture - - - - - - - - - - - - - Authorised - - - - - Authorised - AuthenticateResponse.Authorised - - - - - - - - - LoginInfo - - - - - Login - LoginInfo - LogOn - - - - - - - - - - - Plugin - OpenSim.Framework.Interfaces.IAssetPlugin - - - - - - - - - GetAssetServer - - - - - - - - - - - - - IsTexture - - - - - - - - - - - - - ID - assetID - Id - - - - - - - - - ServerUrl - - - - - ServerKey - - - - - ServerUrl - IAssetServer.SetServerInfo(String, String):Void - - - - - - - - - - - Plugin - OpenSim.Framework.Interfaces.IGridPlugin - - - - - - - - - GetGridServer - - - - - - - - - - - - - ID - sessionID - Id - - - - - ID - agentID - Id - - - - - - - - - GetName - - - - - - - - - ID - sessionID - Id - - - - - ID - agentID - Id - - - - - Logout - LogoutSession - LogOff - - - - - - - - - Neighbours - IGridServer.RequestNeighbours():NeighbourInfo[] - - - - - - - - - IGridServer.RequestUUIDBlock():UUIDBlock - - - - - - - - - ServerUrl - - - - - SendKey - - - - - RecvKey - - - - - IGridServer.SetServerInfo(String, String, String):Void - Recv - RecvKey - - - - - ServerUrl - IGridServer.SetServerInfo(String, String, String):Void - - - - - - - - - - - - - ID - primID - Id - - - - - - - - - ShutDown - method - ShutDown - Shutdown - - - - - - - - - - - Sim - OpenSim.Framework.Interfaces.ISimConfig - - - - - - - - - GetConfigObject - - - - - - - - - - - - - ID - agentID - Id - - - - - - - - - ServerUrl - - - - - SendKey - - - - - RecvKey - - - - - IUserServer.SetServerInfo(String, String, String):Void - Recv - RecvKey - - - - - ServerUrl - IUserServer.SetServerInfo(String, String, String):Void - - - - - - - - - - - - - Logout - LogoutSession - LogOff - - - - - - - - - - - Login - Login - LogOn - - - - - - - - - Agent - - - - - - - - - BaseFolder - - - - - - - - - First - - - - - - - - - InventoryFolder - - - - - - - - - Last - - - - - - - - - SecureSession - - - - - - - - - Session - - - - - - - - - - - Neighbour - OpenSim.Framework.Interfaces.NeighbourInfo - - - - - - - - - regionhandle - - - - - regionhandle - NeighbourInfo.regionhandle - - - - - - - - - RegionLocX - - - - - - - - - RegionLocY - - - - - - - - - sim_ip - - - - - sim - NeighbourInfo.sim_ip - - - - - sim_ip - - - - - - - - - sim_port - - - - - sim - NeighbourInfo.sim_port - - - - - sim_port - - - - - - - - - - - - - agentcircuits - - - - - agentcircuits - - - - - agentcircuits - RemoteGridBase.agentcircuits:Dictionary`2<System.UInt32,OpenSim.Framework.Interfaces.AgentCircuitData> - - - - - - - - - Logout - LogoutSession - LogOff - - - - - - - - - - - Sim - OpenSim.Framework.Interfaces.SimConfig - - - - - - - - - AssetSendKey - - - - - - - - - AssetURL - - - - - - - - - GridRecvKey - - - - - Recv - SimConfig.GridRecvKey - - - - - - - - - GridSendKey - - - - - - - - - GridURL - - - - - - - - - IPListenAddr - - - - - Addr - SimConfig.IPListenAddr - - - - - - - - - IPListenPort - - - - - - - - - RegionHandle - - - - - - - - - RegionLocX - - - - - - - - - RegionLocY - - - - - - - - - RegionName - - - - - - - - - SimConfig.SaveMap(Single[]):Void - heightmap - heightmap - - - - - - - - - UserRecvKey - - - - - Recv - SimConfig.UserRecvKey - - - - - - - - - UserSendKey - - - - - - - - - UserURL - - - - - - - - - - - UUIDBlock - - - - - OpenSim.Framework.Interfaces.UUIDBlock - - - OpenSim.Framework.Interfaces.UUIDBlock - - - - - - - - - BlockEnd - - - - - - - - - BlockStart - - - - - - - - - - - - - - - - - AgentInventory.AgentInventory() - AgentInventory.AgentInventory() AgentInventory.Initialise():Void - - - - - - - - - ID - folderID - Id - - - - - - - - - AgentID - - - - - - - - - ID - folderID - Id - - - - - - - - - Initialise - AgentInventory.Initialise():Void - - - - - - - - - InventoryFolders - - - - - - - - - InventoryItems - - - - - - - - - InventoryRoot - - - - - - - - - LastCached - - - - - - - - - ID - itemID - Id - - - - - - - - - Wearables - - - - - Wearables - AgentInventory.Wearables - - - - - - - - - - - - - AssetID - - - - - - - - - ItemID - - - - - - - - - - - - - DefaultType - - - - - - - - - FolderID - - - - - - - - - FolderName - - - - - - - - - Items - - - - - System.Collections.Generic.List`1<OpenSim.Framework.Inventory.InventoryItem> - InventoryFolder.Items - - - - - - - - - OwnerID - - - - - - - - - ParentID - - - - - - - - - Version - - - - - - - - - - - - - AssetID - - - - - - - - - CreatorID - - - - - - - - - Description - - - - - - - - - FolderID - - - - - - - - - InvType - - - - - - - - - ItemID - - - - - - - - - Name - - - - - - - - - OwnerID - - - - - - - - - Type - - - - - - - - - - - - - - - Sim - OpenSim.Framework.Sims.SimProfile - - - - - - - - - SimProfile.LoadFromGrid(UInt64, String, String, String):SimProfile - System.Exception - - - - - GridURL - - - - - SendKey - - - - - RecvKey - - - - - SimProfile.LoadFromGrid(UInt64, String, String, String):SimProfile - Recv - RecvKey - - - - - region_handle - - - - - GridURL - - - - - RecvKey - SimProfile.LoadFromGrid(UInt64, String, String, String):SimProfile - - - - - SimProfile.LoadFromGrid(UInt64, String, String, String):SimProfile - System.Convert.ToUInt16(System.Object) - System.Convert.ToUInt16(System.Object,System.IFormatProvider) - - - - - SimProfile.LoadFromGrid(UInt64, String, String, String):SimProfile - System.Convert.ToUInt32(System.Object) - System.Convert.ToUInt32(System.Object,System.IFormatProvider) - - - SimProfile.LoadFromGrid(UInt64, String, String, String):SimProfile - System.Convert.ToUInt32(System.Object) - System.Convert.ToUInt32(System.Object,System.IFormatProvider) - - - - - SimProfile.LoadFromGrid(UInt64, String, String, String):SimProfile - System.Convert.ToUInt64(System.Object) - System.Convert.ToUInt64(System.Object,System.IFormatProvider) - - - - - SimProfile.LoadFromGrid(UInt64, String, String, String):SimProfile - System.UInt64.ToString - System.UInt64.ToString(System.IFormatProvider) - - - - - - - - - - - Sim - OpenSim.Framework.Sims.SimProfileBase - - - - - - - - - caps_url - - - - - caps_url - - - - - - - - - recvkey - - - - - recvkey - SimProfileBase.recvkey - - - - - - - - - regionhandle - - - - - regionhandle - SimProfileBase.regionhandle - - - - - - - - - RegionLocX - - - - - - - - - RegionLocY - - - - - - - - - regionname - - - - - regionname - SimProfileBase.regionname - - - - - - - - - sendkey - - - - - sendkey - SimProfileBase.sendkey - - - - - - - - - sim_ip - - - - - sim - SimProfileBase.sim_ip - - - - - sim_ip - - - - - - - - - sim_port - - - - - sim - SimProfileBase.sim_port - - - - - sim_port - - - - - - - - - UUID - - - - - - - - - - - - - - - Heightmap - OpenSim.Framework.Terrain.HeightmapGenHills - - - - - - - - - HeightmapGenHills.GenerateHeightmap(Int32, Single, Single, Boolean):Single[] - num - numHills - - - - - Heightmap - HeightmapGenHills.GenerateHeightmap(Int32, Single, Single, Boolean):Single[] - - - - - - - - - HeightmapGenHills.NumHills - - - - - - - - - - - - - - - - - UserProfile.UserProfile() - IsGridGod - System.Boolean - false - - - - - - - - - Sim - UserProfile.AddSimCircuit(UInt32, LLUUID):Void - - - - - regionUUID - - - - - - - - - AssetURL - - - - - - - - - Circuits - - - - - - - - - CurrentSecureSessionID - - - - - - - - - CurrentSessionID - - - - - - - - - firstname - - - - - firstname - UserProfile.firstname - - - - - - - - - homelookat - - - - - homelookat - UserProfile.homelookat - - - - - - - - - homepos - - - - - homepos - UserProfile.homepos - - - - - - - - - homeregionhandle - - - - - homeregionhandle - UserProfile.homeregionhandle - - - - - - - - - Inventory - - - - - - - - - IsGridGod - - - - - - - - - IsLocal - - - - - - - - - lastname - - - - - lastname - UserProfile.lastname - - - - - - - - - MD5passwd - - - - - - - - - UUID - - - - - - - - - - - - - response - - - - - Customise - UserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - - - - - UserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - GridResp - Nwc.XmlRpc.XmlRpcResponse - - - - - UserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - - - UserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.UInt32.ToString - System.UInt32.ToString(System.IFormatProvider) - - - UserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.UInt32.ToString - System.UInt32.ToString(System.IFormatProvider) - - - - - - - - - DefaultStartupMsg - - - - - - - - - GridRecvKey - - - - - Recv - UserProfileManager.GridRecvKey - - - - - - - - - GridSendKey - - - - - - - - - GridURL - - - - - - - - - UserProfileManager.ParseXMLRPC(String):String - System.Exception - - - - - UserProfileManager.ParseXMLRPC(String):String - - - - - UserProfileManager.ParseXMLRPC(String):String - System.Int32.ToString - System.Int32.ToString(System.IFormatProvider) - - - UserProfileManager.ParseXMLRPC(String):String - System.Int32.ToString - System.Int32.ToString(System.IFormatProvider) - - - - - UserProfileManager.ParseXMLRPC(String):String - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.ParseXMLRPC(String):String - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.ParseXMLRPC(String):String - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.ParseXMLRPC(String):String - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.ParseXMLRPC(String):String - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.ParseXMLRPC(String):String - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.ParseXMLRPC(String):String - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.ParseXMLRPC(String):String - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - UserProfileManager.ParseXMLRPC(String):String - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - - - - - - - UserProfileManager.SetKeys(String, String, String, String):Void - recv - recvKey - - - - - url - UserProfileManager.SetKeys(String, String, String, String):Void - - - - - - - - - - - - - UserProfileManagerBase.AuthenticateUser(String, String, String):Boolean - firstname - firstname - - - - - UserProfileManagerBase.AuthenticateUser(String, String, String):Boolean - lastname - lastname - - - - - UserProfileManagerBase.AuthenticateUser(String, String, String):Boolean - passwd - passwd - - - - - - - - - MD5passwd - - - - - UserProfileManagerBase.CreateNewProfile(String, String, String):UserProfile - firstname - firstname - - - - - UserProfileManagerBase.CreateNewProfile(String, String, String):UserProfile - lastname - lastname - - - - - UserProfileManagerBase.CreateNewProfile(String, String, String):UserProfile - M - MD5passwd - - - - - - - - - ProfileLLUUID - - - - - ProfileLLUUID - - - - - UserProfileManagerBase.GetProfileByLLUUID(LLUUID):UserProfile - - - - - - - - - UserProfileManagerBase.GetProfileByName(String, String):UserProfile - firstname - firstname - - - - - UserProfileManagerBase.GetProfileByName(String, String):UserProfile - lastname - lastname - - - - - - - - - ID - agentID - Id - - - - - - - - - GodID - - - - - ID - GodID - Id - - - - - - - - - UserProfiles - - - - - - - - - - - - - - - OpenSim.Framework.Utilities.BlockingQueue`1 - Queue - - - - - - - - - Util - OpenSim.Framework.Utilities.Util - - - - - Util - - - - - Util - System.Web.Util - - - - - - - - - Xfer - Util.GetNextXferID():UInt32 - - - - - Util.GetNextXferID():UInt32 - - - - - GetNextXferID - - - - - - - - - X - - - - - Y - - - - - Util.UIntsToLong(UInt32, UInt32):UInt64 - X - - - - - Util.UIntsToLong(UInt32, UInt32):UInt64 - Y - - - - - Ints - Util.UIntsToLong(UInt32, UInt32):UInt64 - - - - - - - - - - - - - - - - - - - OpenSim.GridInterfaces.Local - - - - - OpenSim.GridInterfaces.Local - - - - - OpenSim.GridInterfaces.Local - - - - - - - - - - - - - Data - - - - - - - - - Name - - - - - - - - - Type - - - - - - - - - UUID - - - - - - - - - - - AssetUUIDQuery - - - - - - - - - 'asset' - AssetUUIDQuery.Match(AssetStorage):Boolean - - - - - - - - - - - Plugin - OpenSim.GridInterfaces.Local.LocalAssetPlugin - - - - - - - - - - - LocalAssetServer.LocalAssetServer() - System.Exception - - - - - - - - - LocalAssetServer.LoadAsset(AssetBase, Boolean, String):Void - - - - - image - LocalAssetServer.LoadAsset(AssetBase, Boolean, String):Void - - - - - - - - - 'asset' - LocalAssetServer.UploadNewAsset(AssetBase):Void - - - - - - - - - - - Plugin - OpenSim.GridInterfaces.Local.LocalGridPlugin - - - - - - - - - - - Logout - LogoutSession - LogOff - - - - - - - - - Sessions - - - - - System.Collections.Generic.List`1<OpenSim.Framework.Interfaces.Login> - LocalGridServer.Sessions - - - - - - - - - - - - - - - - - - - OpenSim.GridInterfaces.Remote - - - - - OpenSim.GridInterfaces.Remote - - - - - OpenSim.GridInterfaces.Remote - - - - - - - - - - - Plugin - OpenSim.GridInterfaces.Remote.RemoteAssetPlugin - - - - - - - - - Plugin - OpenSim.GridInterfaces.Remote.RemoteGridPlugin - - - - - - - - - - - agentcircuits - - - - - - - - - circuitcode - RemoteGridServer.AuthenticateSession(LLUUID, LLUUID, UInt32):AuthenticateResponse - circuitCode - IGridServer.AuthenticateSession(LLUUID, LLUUID, UInt32):AuthenticateResponse - - - - - - - - - RemoteGridServer.GridRecvKey - - - - - - - - - RemoteGridServer.GridSendKey - - - - - - - - - RemoteGridServer.LogoutSession(LLUUID, LLUUID, UInt32):Boolean - WebRequest.Create(Uri):WebRequest - WebRequest.Create(String):WebRequest - - - - - RemoteGridServer.LogoutSession(LLUUID, LLUUID, UInt32):Boolean - GridResponse - System.String - - - - - Logout - LogoutSession - LogOff - - - - - 'sessionID' - RemoteGridServer.LogoutSession(LLUUID, LLUUID, UInt32):Boolean - - - - - - - - - - - - - - - - - - - OpenSim.Physics.Manager - - - - - OpenSim.Physics.Manager - - - - - OpenSim.Physics.Manager - - - - - - - - - - - Plugin - OpenSim.Physics.Manager.IPhysicsPlugin - - - - - - - - - GetName - - - - - - - - - GetScene - - - - - - - - - - - - - 'heightMap' - NullPhysicsScene.SetTerrain(Single[]):Void - - - - - - - - - NullPhysicsScene.Simulate(Single):Void - System.Int32.ToString - System.Int32.ToString(System.IFormatProvider) - - - - - - - - - - - - - Kinematic - PhysicsActor.Kinematic:Boolean - - - - - - - - - - - - - PhysicsManager.GetPhysicsScene(String):PhysicsScene - System.String.Format(System.String,System.Object) - System.String.Format(System.IFormatProvider,System.String,System.Object[]) - - - - - - - - - Plugins - PhysicsManager.LoadPlugins():Void - - - - - - - - - - - - - PhysicsVector.PhysicsVector(Single, Single, Single) - x - - - - - PhysicsVector.PhysicsVector(Single, Single, Single) - y - - - - - PhysicsVector.PhysicsVector(Single, Single, Single) - z - - - - - - - - - X - - - - - X - PhysicsVector.X - - - - - - - - - Y - - - - - Y - PhysicsVector.Y - - - - - - - - - Z - - - - - Z - PhysicsVector.Z - - - - - - - - - PhysicsVector.Zero - OpenSim.Physics.Manager.PhysicsVector - - - - - - - - - - - - - - - - - - - OpenSim.RegionServer - - - - - OpenSim.RegionServer - - - - - OpenSim.RegionServer - - - - - OpenSim.RegionServer - - - - - OpenSim.RegionServer - - - - - - - - - - - - - ID - transactionID - Id - - - - - - - - - ID - transactionID - Id - - - - - - - - - ID - transactionID - Id - - - - - - - - - ID - assetID - Id - - - - - AgentAssetUpload.HandleUploadPacket(AssetUploadRequestPacket, LLUUID):Void - System.Int32.ToString(System.String) - System.Int32.ToString(System.String,System.IFormatProvider) - - - AgentAssetUpload.HandleUploadPacket(AssetUploadRequestPacket, LLUUID):Void - System.Int32.ToString(System.String) - System.Int32.ToString(System.String,System.IFormatProvider) - - - - - 'assetID' - AgentAssetUpload.HandleUploadPacket(AssetUploadRequestPacket, LLUUID):Void - - - 'pack' - AgentAssetUpload.HandleUploadPacket(AssetUploadRequestPacket, LLUUID):Void - - - - - - - - - AgentAssetUpload.HandleXferPacket(SendXferPacketPacket):Void - xfer - xferPacket - - - - - Xfer - AgentAssetUpload.HandleXferPacket(SendXferPacketPacket):Void - - - - - - - - - - - - - AssetTransaction.AssetTransaction() - UploadComplete - System.Boolean - false - - - - - - - - - AddToInventory - - - - - - - - - Asset - - - - - - - - - InventFolder - - - - - - - - - TransactionID - - - - - - - - - UploadComplete - - - - - - - - - XferID - - - - - Xfer - AssetTransaction.XferID - - - - - - - - - - - Grid - OpenSim.Framework.Grid - - - - - - - - - AssetDll - - - - - - - - - AssetServer - - - - - - - - - GridDll - - - - - - - - - GridServer - - - - - - - - - Initialise - Grid.Initialise():Void - - - - - - - - - Grid.LoadAssetDll(String):IAssetServer - - - - - - - - - Grid.LoadGridDll(String):IGridServer - - - - - - - - - - - Sim - OpenSim.OpenSimApplication - - - - - - - - - OpenSimApplication.RemoveClientCircuit(UInt32):Void - circuitcode - circuitcode - - - - - - - - - OpenSimApplication.SendPacketTo(Byte[], Int32, SocketFlags, UInt32):Void - circuitcode - circuitcode - - - - - - - - - StartUp - method - StartUp - Startup - - - - - - - - - - - Sim - OpenSim.OpenSimMain - - - - - OpenSim.OpenSimMain - System.Timers.Timer, System.Net.Sockets.Socket - - - - - - - - - OpenSimMain.OpenSimMain() - loginserver - System.Boolean - false - - - OpenSimMain.OpenSimMain() - sandbox - System.Boolean - false - - - - - - - - - _physicsEngine - - - - - _physicsEngine - - - - - - - - - OpenSimMain.LoadConfigDll(String):SimConfig - - - - - - - - - loginserver - - - - - loginserver - OpenSimMain.loginserver - - - - - - - - - sandbox - - - - - - - - - Server - - - - - - - - - Timer.set_Interval(Double):Void - OpenSimMain.StartUp():Void - - - - - OpenSimMain.StartUp():Void - System.UInt32.ToString - System.UInt32.ToString(System.IFormatProvider) - - - OpenSimMain.StartUp():Void - System.UInt32.ToString - System.UInt32.ToString(System.IFormatProvider) - - - - - - - - - - - Sim - OpenSim.OpenSimRoot - - - - - - - - - OpenSimRoot.OpenSimRoot() - Sandbox - System.Boolean - false - - - - - - - - - Application - - - - - - - - - AssetCache - - - - - - - - - Cfg - - - - - Cfg - OpenSimRoot.Cfg - - - - - - - - - ClientThreads - - - - - - - - - GridServers - - - - - - - - - HttpServer - - - - - - - - - InventoryCache - - - - - - - - - LocalWorld - - - - - - - - - Sandbox - - - - - - - - - StartUp - method - StartUp - Startup - - - - - - - - - startuptime - - - - - startuptime - OpenSimRoot.startuptime - - - - - - - - - - - Que - OpenSim.QueItem - - - - - - - - - Incoming - - - - - - - - - Packet - - - - - - - - - - - Sim - OpenSim.SimClient - - - - - OpenSim.SimClient - System.Timers.Timer - - - - - - - - - SimClient.SimClient(EndPoint, UseCircuitCodePacket) - Sequence - System.UInt32 - 0 - - - SimClient.SimClient(EndPoint, UseCircuitCodePacket) - debug - System.Boolean - false - - - - - Timer.Timer(Double) - SimClient.SimClient(EndPoint, UseCircuitCodePacket) - - - - - SimClient.SimClient(EndPoint, UseCircuitCodePacket) - initialcirpack - initialcirpack - - - - - - - - - AgentID - - - - - - - - - CircuitCode - - - - - - - - - ClientAvatar - - - - - - - - - NewPack - - - - - - - - - SimClient.newAssetFolder - - - - - - - - - NewPack - - - - - - - - - Pack - - - - - SimClient.ProcessInPacket(Packet):Void - wear - libsecondlife.Packets.AgentIsNowWearingPacket - - - - - op_Equality - "" - SimClient.ProcessInPacket(Packet):Void - - - - - - - - - SimClient.ProcessOutPacket(Packet):Void - System.Exception - - - - - Pack - - - - - - - - - SecureSessionID - - - - - - - - - SessionID - - - - - - - - - userEP - - - - - - - - - - - OpenSim.SimConsole - OpenSim.Framework.Console.ConsoleBase - - - - - Sim - OpenSim.SimConsole - - - - - - - - - SimConsole.SimConsole(ConsoleType, String, Int32) - constype - constype - - - - - SimConsole.SimConsole(ConsoleType, String, Int32) - sparam - sparam - - - - - SimConsole.SimConsole(ConsoleType, String, Int32) - iparam - iparam - - - - - iparam - SimConsole.SimConsole(ConsoleType, String, Int32) - - - - - sparam - SimConsole.SimConsole(ConsoleType, String, Int32) - - - - - - - - - op_Equality - "" - SimConsole.CmdPrompt(String, String):String - - - - - - - - - SimConsole.ConsType - - - - - - - - - SimConsole.MainConsolePrompt():Void - System.UInt64.ToString - System.UInt64.ToString(System.IFormatProvider) - - - - - - - - - 'cmdparams' - SimConsole.RunCmd(String, String[]):Object - - - - - - - - - SimConsole.ShowCommands(String):Void - System.String.Format(System.String,System.Object[]) - System.String.Format(System.IFormatProvider,System.String,System.Object[]) - - - SimConsole.ShowCommands(String):Void - System.String.Format(System.String,System.Object[]) - System.String.Format(System.IFormatProvider,System.String,System.Object[]) - - - - - - - - - - - - - Version - - - - - - - - - - - - - - - - - ID - imageID - Id - - - - - - - - - AssetRequests - - - - - System.Collections.Generic.List`1<OpenSim.Assets.AssetRequest> - AssetCache.AssetRequests - - - - - - - - - Assets - - - - - - - - - sourceAsset - AssetCache.CloneAsset(LLUUID, AssetInfo):AssetInfo - OpenSim.Assets.AssetInfo - OpenSim.Framework.Assets.AssetBase - - - - - AssetCache.CloneAsset(LLUUID, AssetInfo):AssetInfo - - - - - newOwner - AssetCache.CloneAsset(LLUUID, AssetInfo):AssetInfo - - - - - 'sourceAsset' - AssetCache.CloneAsset(LLUUID, AssetInfo):AssetInfo - - - - - - - - - source - AssetCache.CloneImage(LLUUID, TextureImage):TextureImage - OpenSim.Assets.TextureImage - OpenSim.Framework.Assets.AssetBase - - - - - AssetCache.CloneImage(LLUUID, TextureImage):TextureImage - - - - - newOwner - AssetCache.CloneImage(LLUUID, TextureImage):TextureImage - - - - - 'source' - AssetCache.CloneImage(LLUUID, TextureImage):TextureImage - - - - - - - - - ID - agentID - Id - - - - - - - - - ID - assetID - Id - - - - - - - - - RequestedAssets - - - - - - - - - RequestedTextures - - - - - - - - - AssetCache.RunAssetManager():Void - System.Exception - - - - - - - - - TextureRequests - - - - - System.Collections.Generic.List`1<OpenSim.Assets.AssetRequest> - AssetCache.TextureRequests - - - - - - - - - Textures - - - - - - - - - - - OpenSim.Assets.AssetInfo - OpenSim.Framework.Assets.AssetBase - - - - - - - - - AssetInfo.AssetInfo(AssetBase) - a - aBase - - - - - 'aBase' - AssetInfo.AssetInfo(AssetBase) - - - - - - - - - - - - - AssetRequest.AssetRequest() - DataPointer - System.Int64 - 0 - - - AssetRequest.AssetRequest() - NumPackets - System.Int32 - 0 - - - AssetRequest.AssetRequest() - PacketCounter - System.Int32 - 0 - - - - - - - - - AssetInf - - - - - - - - - DataPointer - - - - - - - - - ImageInfo - - - - - - - - - IsTextureRequest - - - - - - - - - NumPackets - - - - - Num - AssetRequest.NumPackets - - - - - - - - - PacketCounter - - - - - - - - - RequestAssetID - - - - - - - - - RequestUser - - - - - - - - - TransferRequestID - - - - - - - - - - - - - ID - folderID - Id - - - - - - - - - ID - clientID - Id - - - - - - - - - ID - folderID - Id - - - - - - - - - ID - folderID - Id - - - - - - - - - FetchItems - - - - - - - - - FetchDescend - - - - - - - - - ID - agentID - Id - - - - - - - - - ID - itemID - Id - - - - - - - - - - - OpenSim.Assets.TextureImage - OpenSim.Framework.Assets.AssetBase - - - - - - - - - TextureImage.TextureImage(AssetBase) - a - aBase - - - - - 'aBase' - TextureImage.TextureImage(AssetBase) - - - - - - - - - - - - - - - Sim - OpenSim.CAPS.SimCAPSHTTPServer - - - - - SimCAPSHTTPServer - - - - - OpenSim.CAPS.SimCAPSHTTPServer - System.Net.HttpListener - - - - - - - - - SimCAPSHTTPServer.HandleRequest(Object):Void - stateinfo - stateinfo - - - - - - - - - HTTPD - - - - - - - - - Listener - - - - - - - - - SimCAPSHTTPServer.LoadAdminPage():Void - System.Exception - - - - - - - - - SimCAPSHTTPServer.ParseLLSDXML(String):String - - - - - requestBody - SimCAPSHTTPServer.ParseLLSDXML(String):String - - - - - - - - - SimCAPSHTTPServer.ParseREST(String, String, String):String - System.Exception - - - - - SimCAPSHTTPServer.ParseREST(String, String, String):String - System.String.Format(System.String,System.Object[]) - System.String.Format(System.IFormatProvider,System.String,System.Object[]) - - - - - - - - - SimCAPSHTTPServer.ParseXMLRPC(String):String - System.Exception - - - - - SimCAPSHTTPServer.ParseXMLRPC(String):String - - - - - SimCAPSHTTPServer.ParseXMLRPC(String):String - System.Convert.ToUInt32(System.Object) - System.Convert.ToUInt32(System.Object,System.IFormatProvider) - - - - - - - - - SimCAPSHTTPServer.StartHTTP():Void - System.Exception - - - - - SimCAPSHTTPServer.StartHTTP():Void - - - - - - - - - - - - - - - - - mesh - - - - - System.Collections.Generic.List`1<OpenSim.types.Triangle> - Mesh.mesh - - - - - - - - - Mesh.op_Addition(Mesh, Mesh):Mesh - a - - - - - Mesh.op_Addition(Mesh, Mesh):Mesh - b - - - - - Add - Mesh.op_Addition(Mesh, Mesh):Mesh - - - - - Mesh - Mesh.op_Addition(Mesh, Mesh):Mesh - - - - - - - - - - - - - A - - - - - B - - - - - C - - - - - Triangle.Triangle(Vector3, Vector3, Vector3) - A - - - - - Triangle.Triangle(Vector3, Vector3, Vector3) - B - - - - - Triangle.Triangle(Vector3, Vector3, Vector3) - C - - - - - - - - - - - - - - - - - LocalUserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Int32.ToString - System.Int32.ToString(System.IFormatProvider) - - - LocalUserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Int32.ToString - System.Int32.ToString(System.IFormatProvider) - - - - - LocalUserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - LocalUserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - LocalUserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - LocalUserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - LocalUserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - LocalUserProfileManager.CustomiseResponse(Hashtable&, UserProfile):Void - System.Single.ToString - System.Single.ToString(System.IFormatProvider) - - - - - - - - - - - OpenSim.UserServer.LoginServer - OpenSim.Framework.Grid.LoginService - - - - - OpenSim.UserServer.LoginServer - System.Net.Sockets.Socket - - - - - Login - LoginServer - LogOn - - - - - - - - - LoginServer.LoginServer(IGridServer) - _needPasswd - System.Boolean - false - - - LoginServer.LoginServer(IGridServer) - userAccounts - System.Boolean - false - - - - - - - - - LoginServer.Authenticate(String, String, String):Boolean - passwd - passwd - - - - - - - - - clientAddress - - - - - - - - - Customise - LoginServer.CustomiseLoginResponse(Hashtable, String, String):Void - - - - - Login - CustomiseLoginResponse - LogOn - - - - - - - - - LoginServer.EncodePassword(String):String - System.String.ToLower - System.String.ToLower(System.Globalization.CultureInfo) - - - - - - - - - LoginServer.GetAgentId(String, String):LLUUID - System.Int32.ToString(System.String) - System.Int32.ToString(System.String,System.IFormatProvider) - - - - - - - - - LoginServer.InitializeLogin():Void - 4 - UserProfileManager.SetKeys(String, String, String, String):Void - Welcome to OpenSim - - - - - Sim - OpenSim - - - - - - - - - LoginServer.LoginRequest(StreamReader, StreamWriter):Void - System.Exception - - - - - LoginServer.LoginRequest(StreamReader, StreamWriter):Void - System.Convert.ToInt32(System.String) - System.Convert.ToInt32(System.String,System.IFormatProvider) - - - - - op_Inequality - "" - LoginServer.LoginRequest(StreamReader, StreamWriter):Void - - - - - - - - - writer - LoginServer.ProcessXmlRequest(XmlRpcRequest, StreamWriter):Boolean - System.IO.StreamWriter - System.IO.TextWriter - - - - - LoginServer.ProcessXmlRequest(XmlRpcRequest, StreamWriter):Boolean - System.Int32.ToString - System.Int32.ToString(System.IFormatProvider) - - - - - LoginServer.ProcessXmlRequest(XmlRpcRequest, StreamWriter):Boolean - System.Int32.ToString(System.String) - System.Int32.ToString(System.String,System.IFormatProvider) - - - - - 'request' - LoginServer.ProcessXmlRequest(XmlRpcRequest, StreamWriter):Boolean - - - 'writer' - LoginServer.ProcessXmlRequest(XmlRpcRequest, StreamWriter):Boolean - - - 'writer' - LoginServer.ProcessXmlRequest(XmlRpcRequest, StreamWriter):Boolean - - - - - - - - - remoteAddress - - - - - - - - - LoginServer.RunLogin():Void - System.Exception - - - LoginServer.RunLogin():Void - System.Exception - - - - - LoginServer.RunLogin():Void - clientEndPoint - System.Net.IPEndPoint - - - - - - - - - - - - - - - - - Avatar.Avatar() - PhysicsEngineFlying - System.Boolean - false - - - - - - - - - Avatar.Avatar(SimClient) - _updateCount - System.Int16 - 0 - - - Avatar.Avatar(SimClient) - avatarAppearanceTexture - libsecondlife.LLObject+TextureEntry - null - - - Avatar.Avatar(SimClient) - movementflag - System.Byte - 0 - - - Avatar.Avatar(SimClient) - updateflag - System.Boolean - false - - - - - TheClient - - - - - - - - - anim_seq - - - - - anim - Avatar.anim_seq - - - - - anim_seq - - - - - - - - - Animations - - - - - - - - - RegionInfo - - - - - RegionInfo - Avatar.CompleteMovement(World):Void - - - - - - - - - ControllingClient - - - - - - - - - current_anim - - - - - anim - Avatar.current_anim - - - - - current_anim - - - - - - - - - firstname - - - - - firstname - Avatar.firstname - - - - - - - - - lastname - - - - - lastname - Avatar.lastname - - - - - - - - - Anims - Avatar.LoadAnims():Void - - - - - - - - - PhysActor - - - - - - - - - PhysicsEngineFlying - - - - - - - - - Anim - Avatar.SendAnimPack():Void - - - - - - - - - 'userInfo' - Avatar.SendAppearanceToOtherAgent(SimClient):Void - - - - - - - - - RegionInfo - - - - - RegionInfo - Avatar.SendRegionHandshake(World):Void - - - - - - - - - - - - - AnimsLLUUID - - - - - Anims - AvatarAnimations.AnimsLLUUID - - - - - - - - - AnimsNames - - - - - Anims - AvatarAnimations.AnimsNames - - - - - - - - - Anims - AvatarAnimations.LoadAnims():Void - - - - - - - - - - - - - Entity.Entity() - localid - System.UInt32 - 0 - - - - - - - - - addForces - - - - - - - - - BackUp - method - BackUp - Backup - - - - - - - - - children - - - - - System.Collections.Generic.List`1<OpenSim.world.Entity> - Entity.children - - - - - - - - - getMesh - - - - - - - - - getName - - - - - - - - - localid - - - - - localid - Entity.localid - - - - - - - - - name - - - - - - - - - position - - - - - - - - - rotation - - - - - - - - - update - - - - - - - - - uuid - - - - - uuid - Entity.uuid - - - - - - - - - velocity - - - - - - - - - - - - - X - - - - - X - NewForce.X - - - - - - - - - Y - - - - - Y - NewForce.Y - - - - - - - - - Z - - - - - Z - NewForce.Z - - - - - - - - - - - 'UpdateFlag' - updateFlag - - - - - - - - - Primitive.Primitive() - dirtyFlag - System.Boolean - false - - - Primitive.Primitive() - mesh_cutbegin - System.Single - 0.0 - - - Primitive.Primitive() - newPrimFlag - System.Boolean - false - - - Primitive.Primitive() - physicsEnabled - System.Boolean - false - - - Primitive.Primitive() - physicstest - System.Boolean - false - - - Primitive.Primitive() - updateFlag - System.Boolean - false - - - - - - - - - localID-702000 - Primitive.CreateFromPacket(ObjectAddPacket, LLUUID, UInt32):Void - - - - - ID - agentID - Id - - - - - ID - localID - Id - - - - - Primitive.CreateFromPacket(ObjectAddPacket, LLUUID, UInt32):Void - System.UInt32.ToString(System.String) - System.UInt32.ToString(System.String,System.IFormatProvider) - - - - - 'addPacket' - Primitive.CreateFromPacket(ObjectAddPacket, LLUUID, UInt32):Void - - - - - - - - - 'store' - Primitive.CreateFromStorage(PrimData):Void - - - - - - - - - dirtyFlag - - - - - - - - - mesh_cutbegin - - - - - cutbegin - Primitive.mesh_cutbegin - - - - - mesh_cutbegin - - - - - - - - - mesh_cutend - - - - - cutend - Primitive.mesh_cutend - - - - - mesh_cutend - - - - - - - - - newPrimFlag - - - - - - - - - PhysActor - - - - - - - - - primData - - - - - - - - - RemoteClient - - - - - 'RemoteClient' - Primitive.UpdateClient(SimClient):Void - - - - - - - - - updateFlag - - - - - - - - - 'pack' - Primitive.UpdateObjectFlags(ObjectFlagUpdatePacket):Void - - - - - - - - - 'addPacket' - Primitive.UpdateShape(ObjectDataBlock):Void - - - - - - - - - - - - - ScriptEngine.ScriptEngine(World) - env - env - - - - - env - ScriptEngine.ScriptEngine(World) - - - - - - - - - ScriptEngine.LoadScript():Void - - - - - - - - - - - - - HeightMap - - - - - - - - - - - World - OpenSim.world - - - - - - - - - World.World() - _localNumber - System.UInt32 - 0 - - - - - - - - - _localNumber - - - - - _localNumber - - - - - - - - - AgentClient - - - - - - - - - AgentClient - - - - - - - - - DeRezPacket - - - - - AgentClient - - - - - World.DeRezObject(DeRezObjectPacket, SimClient):Void - Rez - DeRezPacket - - - - - Rez - World.DeRezObject(DeRezObjectPacket, SimClient):Void - - - - - AgentClient - World.DeRezObject(DeRezObjectPacket, SimClient):Void - - - - - De - World.DeRezObject(DeRezObjectPacket, SimClient):Void - - - - - - - - - Entities - - - - - - - - - RemoteClient - - - - - Prims - World.GetInitialPrims(SimClient):Void - - - - - - - - - LandMap - - - - - - - - - Prims - World.LoadPrimsFromStorage():Void - - - - - - - - - World.LoadStorageDLL(String):Boolean - - - - - - - - - localStorage - - - - - - - - - World.Rand - - - - - - - - - Scripts - - - - - - - - - RemoteClient - - - - - 'RemoteClient' - World.SendLayerData(SimClient):Void - - - 'RemoteClient' - World.SendLayerData(SimClient):Void - - - 'RemoteClient' - World.SendLayerData(SimClient):Void - - - - - - - - - - - - - - - - - IScriptHost.Register(IScript):Boolean - iscript - iscript - - - - - - - - - - - - - - - - - - - OpenSim.Storage.LocalStorageDb4o - - - - - OpenSim.Storage.LocalStorageDb4o - - - - - OpenSim.Storage.LocalStorageDb4o - - - - - - - - - - - - - Db4LocalStorage.Db4LocalStorage() - System.Exception - - - - - - - - - 'receiver' - Db4LocalStorage.LoadPrimitives(ILocalStorageReceiver):Void - - - - - - - - - 'prim' - Db4LocalStorage.StorePrim(PrimData):Void - - - - - - - - - - - UUIDQuery - - - - - - - - - 'prim' - UUIDQuery.Match(PrimData):Boolean - - - - - - - - - - - - - - - - - - - OpenSim.Physics.BasicPhysicsPlugin - - - - - - - - - - OpenSim.Physics.BasicPhysicsPlugin - - - - - - - - - - OpenSim.Physics.BasicPhysicsPlugin - - - - - - - - - - - - - - - - - - BasicActor.flying - - - - - - - - - BasicActor.SetAcceleration(PhysicsVector):Void - accel - accel - - - - - - - - - - - Plugin - OpenSim.Physics.BasicPhysicsPlugin.BasicPhysicsPlugin - - - - - BasicPhysicsPlugin - OpenSim.Physics.BasicPhysicsPlugin - - - - - - - - - - - - - - - - - OpenSim.Physics.OdePlugin - - - - - OpenSim.Physics.OdePlugin - - - - - OpenSim.Physics.OdePlugin - - - - - - - - - - - OdeCharacter - - - - - - - - - parent_scene - OdeCharacter.OdeCharacter(OdeScene, PhysicsVector) - - - - - 'pos' - OdeCharacter.OdeCharacter(OdeScene, PhysicsVector) - - - - - - - - - OdeCharacter.capsule_geom - - - - - - - - - OdeCharacter.gravityAccel - - - - - - - - - OdeCharacter.SetAcceleration(PhysicsVector):Void - accel - accel - - - - - - - - - - - Plugin - OpenSim.Physics.OdePlugin.OdePlugin - - - - - OdePlugin - OpenSim.Physics.OdePlugin - - - - - - - - - - - OdePrim._position - - - - - - - - - OdePrim.SetAcceleration(PhysicsVector):Void - accel - accel - - - - - - - - - - - - - 'position' - OdeScene.AddPrim(PhysicsVector, PhysicsVector):PhysicsActor - - - 'size' - OdeScene.AddPrim(PhysicsVector, PhysicsVector):PhysicsActor - - - - - - - - - OdeScene.Land - - - - - - - - - OdeScene.LandGeom - - - - - - - - - 'heightMap' - OdeScene.SetTerrain(Single[]):Void - - - 'heightMap' - OdeScene.SetTerrain(Single[]):Void - - - - - - - - - space - - - - - space - - - - - - - - - world - - - - - world - - - - - - - - - - - - - - - - - - - OpenSim.Physics.PhysXPlugin - - - - - OpenSim.Physics.PhysXPlugin - - - - - OpenSim.Physics.PhysXPlugin - - - - - - - - - - - - - PhysXCharacter.SetAcceleration(PhysicsVector):Void - accel - accel - - - - - - - - - - - Plugin - OpenSim.Physics.PhysXPlugin.PhysXPlugin - - - - - PhysXPlugin - OpenSim.Physics.PhysXPlugin - - - - - - - - - - - PhysXPrim._position - - - - - - - - - PhysXPrim.SetAcceleration(PhysicsVector):Void - accel - accel - - - - - - - - - - - - - - - - Save it for a rainy day. - Save it for a rainy day. - Save it for a rainy day. - - - - - No valid permission requests were found for assembly '{0}'. You should always specify the minimum security permissions using SecurityAction.RequestMinimum. - - - Sign '{0}' with a strong name key. - - - Consider merging the types defined in '{0}' with another namespace. - - - It appears that field '{0}' is never used or is only ever assigned to. Use this field or remove it. - - - Change '{0}' to be read-only by removing the property setter. - - - The compound word '{0}' in {1} '{2}' exists as a discrete term. If your usage is intended to be single word, case it as '{3}'. - - - '{0}' is marked ComVisible(true) but has the following ComVisible(false) types in its object hierarchy: {1} - - - Consider changing the type of parameter '{0}' in {1} from {2} to its base type {3}. This method appears to only require base class members in its implementation. Suppress this violation if there is a compelling reason to require the more derived type in the method signature. - - - '{0}' contains a call chain that results in a call to a virtual method defined by the class. Review the following call stack for unintended consequences: {1} - - - Modify '{0}' to catch a more specific exception than '{1}' or rethrow the exception. - - - Remove the readonly declaration from '{0}' or change the field to one that is an immutable reference type. If the reference type '{1}' is, in fact, immutable, exclude this message. - - - Make '{0}' private or internal (Friend in VB, public private in C++) and provide a public or protected property to access it. - - - Change '{0}' in {1} to use Collection<T>, ReadOnlyCollection<T> or KeyedCollection<K,V> - - - {0} initializes field {1} of type {2} to {3}. Remove this initialization as it will be done automatically by the runtime. - - - {0} passes a literal as parameter {1} of a call to {2}. Retrieve the following string argument from a resource table instead: '{3}' - - - Consider a design that does not require that '{0}' be a reference parameter. - - - {0} creates an exception of type '{1}', an exception type that is not sufficiently specific and should never be raised by user code. If this exception instance might be thrown, use a different exception type. - - - Modify the call to {0} in method {1} to set the timer interval to a value that's greater than or equal to one second. - - - Correct the casing of member name '{0}'. - Correct the casing of namespace name '{0}'. - Correct the casing of parameter name '{0}'. - Correct the casing of type name '{0}'. - - - Correct the spelling of the unrecognized token '{0}' in member name '{1}'. - Consider providing a more meaningful name than the one-letter token '{0}' in member name '{1}'. - Correct the spelling of the unrecognized token '{0}' in namespace '{1}'. - In method {0}, correct the spelling of the unrecognized token '{1}' in parameter name '{2}' or strip it entirely if it represents any sort of hungarian notation. - In method {0}, consider providing a more meaningful name than the one-letter parameter name '{1}'. - Correct the spelling of the unrecognized token '{0}' in type name '{1}'. - - - Change member names {0} and '{1}' so that they differ by more than case. - - - Remove all underscores from member '{0}'. - Remove all underscores from parameter '{0}'. - Remove all underscores from type '{0}'. - - - Rename '{0}' so that it does not end in '{1}'. - - - Correct the spelling of the unrecognized token '{0}' in the literal '{1}'. - - - Correct the capitalization of member name '{0}'. - Correct the capitalization of namespace name '{0}'. - Correct the capitalization of parameter name '{0}'. - Correct the capitalization of type name '{0}'. - - - Add an AssemblyVersion attribute to '{0}'. - - - '{0}' should be marked with CLSCompliantAttribute and its value should be true. - - - Mark '{0}' as ComVisible(false) at the assembly level, then mark all types within the assembly that should be exposed to Com clients as ComVisible(true). - - - The 'this' parameter (or 'Me' in VB) of {0} is never used. Mark the member as static (or Shared in VB) or use 'this'/'Me' in the method body or at least one property accessor, if appropriate. - - - Consider making '{0}' non-public or a constant. - - - Correct the potential overflow in the operation '{0}' in '{1}'. - - - Provide a method named '{0}' as a friendly alternate for operator {1}. - - - Consider adding an overload of the equality operator for '{0}' that takes the same parameters as {1}. - - - '{0}' should override Equals. - '{0}' should override the equality (==) and inequality (!=) operators. - - - Change parameter name '{0}' of method {1} to '{2}' in order to match the identifier as it has been declared in {3}. - - - Modify {0} to call {1} instead of {2}. - - - Make '{0}' private. - - - Add a property getter to '{0}'. - - - {0} declares a local, '{1}', of type {2}, which is never used or is only assigned to. Use this local or remove it. - - - Parameter '{0}' of {1} is never used. Remove the parameter or use it in the method body. - - - Correct the capitalization of '{0}' in member name '{1}'. - 'Id' is an abbreviation and therefore is not subject to acronym casing guidelines. Correct the capitalization of 'ID' in member name '{0}' by changing it to 'Id'. - 'Id' is an abbreviation and therefore is not subject to acronym casing guidelines. Correct the capitalization of '{0}' in parameter name '{1}' by changing it to '{2}'. - Correct the capitalization of '{0}' in type name '{1}'. - - - {0} makes a call to {1} that does not explicitly provide a CultureInfo. This should be replaced with a call to {2}. - - - {0} makes a call to {1} that does not explicitly provide an IFormatProvider. This should be replaced with a call to {2}. - - - Remove the public constructors from '{0}'. - - - Replace the call to String.{0}({1}) in '{2}' with a call to String.IsNullOrEmpty. - - - The type name '{0}' conflicts in whole or in part with the namespace name '{1}'. Change either name to eliminate the conflict. - - - Implement IDisposable on '{0}' as it instantiates members of the following IDisposable types: {1} - - - Implement IDisposable on '{0}'. - - - Change the type of parameter '{0}' of method {1} from string to System.Uri, or provide an overload of {1}, that allows '{0}' to be passed as a System.Uri object. - - - Replace the term '{0}' in member name '{1}' with the preferred alternate '{2}'. - Replace the term '{0}' in type name '{1}' with the preferred alternate '{2}'. - - - Change '{0}' to a property if appropriate. - - - Validate parameter {0} passed to externally visible method {1}. - - - - From 4a7b8c1b41972a8ea40f08b57d3111d59505748b Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 12 Nov 2016 03:31:34 +0000 Subject: [PATCH 042/305] ubOde fix a multhreading timming issue --- OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs b/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs index 3403f4baac..60b24ec891 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs @@ -1157,6 +1157,8 @@ namespace OpenSim.Region.PhysicsModule.ubOde m_building = true; // control must set this to false when done + AddChange(changes.Add, null); + // get basic mass parameters ODEPhysRepData repData = _parent_scene.m_meshWorker.NewActorPhysRep(this, _pbs, _size, m_shapetype); @@ -1165,8 +1167,6 @@ namespace OpenSim.Region.PhysicsModule.ubOde m_OBBOffset = repData.OBBOffset; UpdatePrimBodyData(); - - AddChange(changes.Add, null); } private void resetCollisionAccounting() From b6329fb784669e60f0eacb9610fd70e7f551453c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 12 Nov 2016 14:07:40 +0000 Subject: [PATCH 043/305] mantis 8055: fix default value of npc options --- bin/OpenSim.ini.example | 16 ++++++++-------- bin/OpenSimDefaults.ini | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index f6466b566d..5103e7184d 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -1132,21 +1132,21 @@ ;; several options to control NPCs creation - ;# {AllowNotOwned} {} {allow NPCs to be created not Owned} {true false} false + ;# {AllowNotOwned} {} {allow NPCs to be created not Owned} {true false} true ;; allow NPCs to be created not Owned {true false} default: true - ; AllowNotOwned = false + ; AllowNotOwned = true - ;# {AllowSenseAsAvatar} {} {allow NPCs to set to be sensed as Avatars} {true false} false + ;# {AllowSenseAsAvatar} {} {allow NPCs to set to be sensed as Avatars} {true false} true ;; allow NPCs to set to be sensed as Avatars {true false} default: true - ; AllowSenseAsAvatar = false + ; AllowSenseAsAvatar = true - ;# {AllowCloneOtherAvatars} {} {allow NPCs to created cloning any avatar in region} {true false} false + ;# {AllowCloneOtherAvatars} {} {allow NPCs to created cloning any avatar in region} {true false} true ;; allow NPCs to created cloning any avatar in region {true false} default: true - ; AllowCloneOtherAvatars = false + ; AllowCloneOtherAvatars = true - ;# {NoNPCGroup} {} {if true NPCs will have no group title, if false display "- NPC -"} {true false} false + ;# {NoNPCGroup} {} {if true NPCs will have no group title, if false display "- NPC -"} {true false} true ;; if true NPCs will have no group title, if false display "- NPC -" for easy identification {true false} default: true - ; NoNPCGroup = false + ; NoNPCGroup = true [Terrain] diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 906c7bc143..35530027ea 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -2126,16 +2126,16 @@ ;; several options to control NPCs creation ;; allow NPCs to be created not Owned {true false} default: true - ; AllowNotOwned = false + ; AllowNotOwned = true ;; allow NPCs to set to be sensed as Avatars {true false} default: true - ; AllowSenseAsAvatar = false + ; AllowSenseAsAvatar = true ;; allow NPCs to created cloning any avatar in region {true false} default: true - ; AllowCloneOtherAvatars = false + ; AllowCloneOtherAvatars = true ;; if true NPCs will have no group title, if false display "- NPC -" for easy identification {true false} default: true - ; NoNPCGroup = false + ; NoNPCGroup = true [Terrain] ; Values can be "pinhead-island" or "flat" From e13ff5a39233fd871e69f9ace23b4559cdfdcb7f Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 13 Nov 2016 11:19:54 -0800 Subject: [PATCH 044/305] BulletSim: update avatar velocity setting to the new TargetVelocity pattern. Now PhysicsActor.Velocity.set and PhysicsActor.SetMomentum do the same thing of setting the instantanious avatar velocity. PhysicsActor.TargetVelocity sets a velocity target and the movement motor is used to accelerate the' avatar to that velocity. --- .../BulletS/BSActorAvatarMove.cs | 8 +--- .../PhysicsModules/BulletS/BSCharacter.cs | 47 ++++++++----------- .../PhysicsModules/BulletS/BSPhysObject.cs | 34 ++++++++++---- .../Region/PhysicsModules/BulletS/BSPrim.cs | 11 ----- 4 files changed, 48 insertions(+), 52 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs index 79ee00f4ca..40c6b983b0 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs @@ -108,10 +108,6 @@ public class BSActorAvatarMove : BSActor { if (m_velocityMotor != null) { -// if (targ == OMV.Vector3.Zero) -// Util.PrintCallStack(); -// -// Console.WriteLine("SetVelocityAndTarget, {0} {1}", vel, targ); m_velocityMotor.Reset(); m_velocityMotor.SetTarget(targ); m_velocityMotor.SetCurrent(vel); @@ -128,7 +124,7 @@ public class BSActorAvatarMove : BSActor m_waitingForLowVelocityForStationary = true; } - // If a movement motor has not been created, create one and start the hovering. + // If a movement motor has not been created, create one and start the movement private void ActivateAvatarMove() { if (m_velocityMotor == null) @@ -161,7 +157,7 @@ public class BSActorAvatarMove : BSActor } } - // Called just before the simulation step. Update the vertical position for hoverness. + // Called just before the simulation step. private void Mover(float timeStep) { // Don't do movement while the object is selected. diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs index 757f06ccd3..6322695e17 100644 --- a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs @@ -449,6 +449,7 @@ public sealed class BSCharacter : BSPhysObject public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } + // PhysicsActor.TargetVelocity // Sets the target in the motor. This starts the changing of the avatar's velocity. public override OMV.Vector3 TargetVelocity { @@ -459,7 +460,7 @@ public sealed class BSCharacter : BSPhysObject set { DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); - m_targetVelocity = value; + base.m_targetVelocity = value; OMV.Vector3 targetVel = value; if (_setAlwaysRun && !_flying) targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f); @@ -472,32 +473,12 @@ public sealed class BSCharacter : BSPhysObject public override OMV.Vector3 Velocity { get { return RawVelocity; } set { - RawVelocity = value; - OMV.Vector3 vel = RawVelocity; - - DetailLog("{0}: set Velocity = {1}", LocalID, value); - - PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate() + if (m_moveActor != null) { - if (m_moveActor != null) - m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */); - - DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel); - ForceVelocity = vel; - }); - } - } - - public override OMV.Vector3 ForceVelocity { - get { return RawVelocity; } - set { - PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); -// Util.PrintCallStack(); - DetailLog("{0}: set ForceVelocity = {1}", LocalID, value); - - RawVelocity = value; - PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); - PhysScene.PE.Activate(PhysBody, true); + // m_moveActor.SetVelocityAndTarget(OMV.Vector3.Zero, OMV.Vector3.Zero, false /* inTaintTime */); + m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false /* inTaintTime */); + } + base.Velocity = value; } } @@ -506,11 +487,23 @@ public sealed class BSCharacter : BSPhysObject { if (m_moveActor != null) { - m_moveActor.SetVelocityAndTarget(OMV.Vector3.Zero, OMV.Vector3.Zero, false /* inTaintTime */); + // m_moveActor.SetVelocityAndTarget(OMV.Vector3.Zero, OMV.Vector3.Zero, false /* inTaintTime */); + m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false /* inTaintTime */); } base.SetMomentum(momentum); } + public override OMV.Vector3 ForceVelocity { + get { return RawVelocity; } + set { + PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); + DetailLog("{0}: BSCharacter.ForceVelocity.set = {1}", LocalID, value); + + RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); + PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); + PhysScene.PE.Activate(PhysBody, true); + } + } public override OMV.Vector3 Torque { get { return RawTorque; } diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs index 3682455154..a846869983 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs @@ -230,15 +230,22 @@ public abstract class BSPhysObject : PhysicsActor // Update the physical location and motion of the object. Called with data from Bullet. public abstract void UpdateProperties(EntityProperties entprop); + // The position value as known by BulletSim. Does not effect the physics engine. public virtual OMV.Vector3 RawPosition { get; set; } + // Set position in BulletSim and the physics engined to a value immediately. Must be called at taint time. public abstract OMV.Vector3 ForcePosition { get; set; } + // The orientation value as known by BulletSim. Does not effect the physics engine. public virtual OMV.Quaternion RawOrientation { get; set; } + // Set orientation in BulletSim and the physics engine to a value immediately. Must be called at taint time. public abstract OMV.Quaternion ForceOrientation { get; set; } + // The velocity value as known by BulletSim. Does not effect the physics engine. public virtual OMV.Vector3 RawVelocity { get; set; } + // Set velocity in BulletSim and the physics engined to a value immediately. Must be called at taint time. public abstract OMV.Vector3 ForceVelocity { get; set; } + // The rotational velocity value as known by BulletSim. Does not effect the physics engine. public OMV.Vector3 RawRotationalVelocity { get; set; } // RawForce is a constant force applied to object (see Force { set; } ) @@ -252,17 +259,28 @@ public abstract class BSPhysObject : PhysicsActor public abstract void AddAngularForce(bool inTaintTime, OMV.Vector3 force); public abstract void AddForce(bool inTaintTime, OMV.Vector3 force); + // PhysicsActor.Velocity + public override OMV.Vector3 Velocity + { + get { return RawVelocity; } + set + { + // This sets the velocity now. BSCharacter will override to clear target velocity + // before calling this. + RawVelocity = value; + PhysScene.TaintedObject(LocalID, TypeName + ".SetVelocity", delegate () { + // DetailLog("{0},BSPhysObject.Velocity.set,vel={1}", LocalID, RawVelocity); + ForceVelocity = RawVelocity; + }); + } + } + // PhysicsActor.SetMomentum - // All the physics engined use this as a way of forcing the velocity to something. + // All the physics engines use this as a way of forcing the velocity to something. + // BSCharacter overrides this so it can set the target velocity to zero before calling this. public override void SetMomentum(OMV.Vector3 momentum) { - // This doesn't just set Velocity=momentum because velocity is ramped up to (see MoveActor) - RawVelocity = momentum; - PhysScene.TaintedObject(LocalID, TypeName + ".SetMomentum", delegate() - { - // DetailLog("{0},BSPrim.SetMomentum,taint,vel={1}", LocalID, RawVelocity); - ForceVelocity = RawVelocity; - }); + this.Velocity = momentum; } public override OMV.Vector3 RotationalVelocity { diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs index 78a617d731..db2b9db987 100644 --- a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs @@ -787,17 +787,6 @@ public class BSPrim : BSPhysObject } } } - public override OMV.Vector3 Velocity { - get { return RawVelocity; } - set { - RawVelocity = value; - PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate() - { - // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); - ForceVelocity = RawVelocity; - }); - } - } public override OMV.Vector3 ForceVelocity { get { return RawVelocity; } set { From 4ebb4e371f44e8e8e9612d8e5eaab274263a2f89 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 13 Nov 2016 19:25:32 +0000 Subject: [PATCH 045/305] prevent self call to llSetScriptState(ownname,FALSE) from blocking entire engine --- .../ScriptEngine/Interfaces/IScriptEngine.cs | 2 +- .../Shared/Api/Implementation/LSL_Api.cs | 2 +- OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 14 +++++++++++--- OpenSim/Tests/Common/Mock/MockScriptEngine.cs | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs index 6355669e16..361a0b9629 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs @@ -68,7 +68,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces void SetMinEventDelay(UUID itemID, double delay); int GetStartParameter(UUID itemID); - void SetScriptState(UUID itemID, bool state); + void SetScriptState(UUID itemID, bool state, bool self); bool GetScriptState(UUID itemID); void SetState(UUID itemID, string newState); void ApiResetScript(UUID itemID); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index bafee28fb3..af0495119f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -521,7 +521,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((item = GetScriptByName(name)) != UUID.Zero) { - m_ScriptEngine.SetScriptState(item, run == 0 ? false : true); + m_ScriptEngine.SetScriptState(item, run == 0 ? false : true, item == m_item.ItemID); } else { diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index e12f8509bc..7822df9c80 100755 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -1854,15 +1854,23 @@ namespace OpenSim.Region.ScriptEngine.XEngine return instance; } - public void SetScriptState(UUID itemID, bool running) + public void SetScriptState(UUID itemID, bool running, bool self) { IScriptInstance instance = GetInstance(itemID); if (instance != null) { if (running) - instance.Start(); + instance.Start(); else - instance.Stop(100); + { + if(self) + { + instance.Running = false; + throw new EventAbortException(); + } + else + instance.Stop(100); + } } } diff --git a/OpenSim/Tests/Common/Mock/MockScriptEngine.cs b/OpenSim/Tests/Common/Mock/MockScriptEngine.cs index d7a144c886..b6f5760d9b 100644 --- a/OpenSim/Tests/Common/Mock/MockScriptEngine.cs +++ b/OpenSim/Tests/Common/Mock/MockScriptEngine.cs @@ -221,7 +221,7 @@ namespace OpenSim.Tests.Common throw new System.NotImplementedException (); } - public void SetScriptState(UUID itemID, bool state) + public void SetScriptState(UUID itemID, bool state, bool self) { throw new System.NotImplementedException (); } From ae17b5d203677ff99cf0c3ee9d9ec9309600b568 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 14 Nov 2016 03:21:07 +0000 Subject: [PATCH 046/305] reduce calls to physics world cast rays for camera collision check --- OpenSim/Framework/AgentUpdateArgs.cs | 1 + .../ClientStack/Linden/UDP/LLClientView.cs | 8 +- .../Region/Framework/Scenes/ScenePresence.cs | 97 +++++++++---------- 3 files changed, 55 insertions(+), 51 deletions(-) diff --git a/OpenSim/Framework/AgentUpdateArgs.cs b/OpenSim/Framework/AgentUpdateArgs.cs index 660bc327de..eaa7902d8d 100644 --- a/OpenSim/Framework/AgentUpdateArgs.cs +++ b/OpenSim/Framework/AgentUpdateArgs.cs @@ -81,6 +81,7 @@ namespace OpenSim.Framework public Vector3 ClientAgentPosition; public bool UseClientAgentPosition; + public bool NeedsCameraCollision; public AgentUpdateArgs() { diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 99c9049e01..46c6a19e9d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -6263,7 +6263,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP bool movement = CheckAgentMovementUpdateSignificance(x); bool camera = CheckAgentCameraUpdateSignificance(x); - + // Was there a significant movement/state change? if (movement) { @@ -6274,6 +6274,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; m_thisAgentUpdateArgs.State = x.State; + m_thisAgentUpdateArgs.NeedsCameraCollision = !camera; + UpdateAgent handlerAgentUpdate = OnAgentUpdate; UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; @@ -6282,7 +6284,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (handlerAgentUpdate != null) OnAgentUpdate(this, m_thisAgentUpdateArgs); - + } // Was there a significant camera(s) change? @@ -6293,6 +6295,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; + m_thisAgentUpdateArgs.NeedsCameraCollision = true; + UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate; if (handlerAgentCameraUpdate != null) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index f96fb858ec..2ca218c387 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2297,6 +2297,48 @@ namespace OpenSim.Region.Framework.Scenes /// /// + private void checkCameraCollision() + { + if(!m_scene.PhysicsScene.SupportsRayCast()) + return; + + ++m_movementUpdateCount; + if (m_movementUpdateCount < 1) + m_movementUpdateCount = 1; + + if (m_doingCamRayCast || m_movementUpdateCount % NumMovementsBetweenRayCast != 0) + return; + + if (m_followCamAuto && !m_mouseLook) + { + Vector3 posAdjusted = AbsolutePosition; +// posAdjusted.Z += 0.5f * Appearance.AvatarSize.Z - 0.5f; + posAdjusted.Z += 1.0f; // viewer current camera focus point + Vector3 tocam = CameraPosition - posAdjusted; + tocam.X = (float)Math.Round(tocam.X, 1); + tocam.Y = (float)Math.Round(tocam.Y, 1); + tocam.Z = (float)Math.Round(tocam.Z, 1); + + float distTocamlen = tocam.Length(); + if (distTocamlen > 0.3f) + { + tocam *= (1.0f / distTocamlen); + posAdjusted.X = (float)Math.Round(posAdjusted.X, 1); + posAdjusted.Y = (float)Math.Round(posAdjusted.Y, 1); + posAdjusted.Z = (float)Math.Round(posAdjusted.Z, 1); + + m_doingCamRayCast = true; + m_scene.PhysicsScene.RaycastWorld(posAdjusted, tocam, distTocamlen + 1.0f, RayCastCameraCallback); + } + } + else if (CameraConstraintActive) + { + Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right... + UpdateCameraCollisionPlane(plane); + CameraConstraintActive = false; + } + } + private void UpdateCameraCollisionPlane(Vector4 plane) { if (m_lastCameraCollisionPlane != plane) @@ -2442,38 +2484,8 @@ namespace OpenSim.Region.Framework.Scenes // Raycast from the avatar's head to the camera to see if there's anything blocking the view // this exclude checks may not be complete - - if (m_movementUpdateCount % NumMovementsBetweenRayCast == 0 && m_scene.PhysicsScene.SupportsRayCast()) - { - if (!m_doingCamRayCast && !m_mouseLook && ParentID == 0) - { - Vector3 posAdjusted = AbsolutePosition; -// posAdjusted.Z += 0.5f * Appearance.AvatarSize.Z - 0.5f; - posAdjusted.Z += 1.0f; // viewer current camera focus point - Vector3 tocam = CameraPosition - posAdjusted; - tocam.X = (float)Math.Round(tocam.X, 1); - tocam.Y = (float)Math.Round(tocam.Y, 1); - tocam.Z = (float)Math.Round(tocam.Z, 1); - - float distTocamlen = tocam.Length(); - if (distTocamlen > 0.3f) - { - tocam *= (1.0f / distTocamlen); - posAdjusted.X = (float)Math.Round(posAdjusted.X, 1); - posAdjusted.Y = (float)Math.Round(posAdjusted.Y, 1); - posAdjusted.Z = (float)Math.Round(posAdjusted.Z, 1); - - m_doingCamRayCast = true; - m_scene.PhysicsScene.RaycastWorld(posAdjusted, tocam, distTocamlen + 1.0f, RayCastCameraCallback); - } - } - else if (CameraConstraintActive && (m_mouseLook || ParentID != 0)) - { - Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right... - UpdateCameraCollisionPlane(plane); - CameraConstraintActive = false; - } - } + if(agentData.NeedsCameraCollision && ParentID == 0) // condition parentID may be wrong + checkCameraCollision(); uint flagsForScripts = (uint)flags; flags = RemoveIgnoredControls(flags, IgnoredControls); @@ -2742,14 +2754,10 @@ namespace OpenSim.Region.Framework.Scenes // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); if (IsChildAgent) - { - // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); return; - } - ++m_movementUpdateCount; - if (m_movementUpdateCount < 1) - m_movementUpdateCount = 1; + if(IsInTransit) + return; // AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; @@ -2779,17 +2787,8 @@ namespace OpenSim.Region.Framework.Scenes m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f) && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false; - - //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto); - // Raycast from the avatar's head to the camera to see if there's anything blocking the view - if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast()) - { - if (m_followCamAuto) - { - Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT; - m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback); - } - } + if(agentData.NeedsCameraCollision) + checkCameraCollision(); TriggerScenePresenceUpdated(); } From e304acb06fddfd79ceedd6991f4c9f1a3fd08e79 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 14 Nov 2016 05:15:41 +0000 Subject: [PATCH 047/305] fix unack bytes stats report --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 246f003dd2..d59b7614ed 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -161,6 +161,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Total byte count of unacked packets sent to this client public int UnackedBytes; + private int m_packetsUnAckReported; /// Total number of received packets that we have reported to the OnPacketStats event(s) private int m_packetsReceivedReported; /// Total number of sent packets that we have reported to the OnPacketStats event(s) @@ -389,11 +390,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP { int newPacketsReceived = PacketsReceived - m_packetsReceivedReported; int newPacketsSent = PacketsSent - m_packetsSentReported; - + int newPacketUnAck = UnackedBytes - m_packetsUnAckReported; callback(newPacketsReceived, newPacketsSent, UnackedBytes); m_packetsReceivedReported += newPacketsReceived; m_packetsSentReported += newPacketsSent; + m_packetsUnAckReported += newPacketUnAck; } } From a858804b420f700965abf3b6601b83c0fb1d9b7c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 14 Nov 2016 22:08:39 +0000 Subject: [PATCH 048/305] fix a vector range parsing --- .../CoreModules/World/Objects/Commands/ObjectCommandsModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs index e65f860e44..688648b965 100644 --- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs @@ -920,7 +920,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands return false; } - string rawConsoleEndVector = rawComponents.Skip(2).Take(1).Single(); + string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single(); if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) { From 8196f21af9ce53a0daf9cd415de06db2e0eff75a Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 14 Nov 2016 22:13:02 +0000 Subject: [PATCH 049/305] change camera collision check rules --- .../Region/Framework/Scenes/ScenePresence.cs | 57 +++++++++++-------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 2ca218c387..3378eade7c 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2313,25 +2313,23 @@ namespace OpenSim.Region.Framework.Scenes { Vector3 posAdjusted = AbsolutePosition; // posAdjusted.Z += 0.5f * Appearance.AvatarSize.Z - 0.5f; + // not good for tiny or huge avatars posAdjusted.Z += 1.0f; // viewer current camera focus point Vector3 tocam = CameraPosition - posAdjusted; - tocam.X = (float)Math.Round(tocam.X, 1); - tocam.Y = (float)Math.Round(tocam.Y, 1); - tocam.Z = (float)Math.Round(tocam.Z, 1); - float distTocamlen = tocam.Length(); - if (distTocamlen > 0.3f) + float distTocamlen = tocam.LengthSquared(); + if (distTocamlen > 0.08f && distTocamlen < 400) { + distTocamlen = (float)Math.Sqrt(distTocamlen); tocam *= (1.0f / distTocamlen); - posAdjusted.X = (float)Math.Round(posAdjusted.X, 1); - posAdjusted.Y = (float)Math.Round(posAdjusted.Y, 1); - posAdjusted.Z = (float)Math.Round(posAdjusted.Z, 1); m_doingCamRayCast = true; m_scene.PhysicsScene.RaycastWorld(posAdjusted, tocam, distTocamlen + 1.0f, RayCastCameraCallback); + return; } } - else if (CameraConstraintActive) + + if (CameraConstraintActive) { Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right... UpdateCameraCollisionPlane(plane); @@ -2350,17 +2348,14 @@ namespace OpenSim.Region.Framework.Scenes public void RayCastCameraCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 pNormal) { - const float POSITION_TOLERANCE = 0.02f; - const float ROTATION_TOLERANCE = 0.02f; +// const float POSITION_TOLERANCE = 0.02f; +// const float ROTATION_TOLERANCE = 0.02f; - m_doingCamRayCast = false; if (hitYN && localid != LocalId) { - SceneObjectGroup group = m_scene.GetGroupByPrim(localid); - bool IsPrim = group != null; - if (IsPrim) + if (localid != 0) { - SceneObjectPart part = group.GetPart(localid); + SceneObjectPart part = m_scene.GetSceneObjectPart(localid); if (part != null && !part.VolumeDetectActive) { CameraConstraintActive = true; @@ -2393,13 +2388,16 @@ namespace OpenSim.Region.Framework.Scenes UpdateCameraCollisionPlane(plane); } } - else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) || - !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE)) +// else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) || +// !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE)) + else if(CameraConstraintActive) { Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -9000f); // not right... UpdateCameraCollisionPlane(plane); CameraConstraintActive = false; } + + m_doingCamRayCast = false; } /// @@ -2767,7 +2765,7 @@ namespace OpenSim.Region.Framework.Scenes // Use these three vectors to figure out what the agent is looking at // Convert it to a Matrix and/or Quaternion - // this my need lock + // this may need lock CameraAtAxis = agentData.CameraAtAxis; CameraLeftAxis = agentData.CameraLeftAxis; CameraUpAxis = agentData.CameraUpAxis; @@ -2781,11 +2779,24 @@ namespace OpenSim.Region.Framework.Scenes DrawDistance = agentData.Far; - // Check if Client has camera in 'follow cam' or 'build' mode. - Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation); - m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f) - && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false; + // Check if Client has camera in 'follow cam' or 'build' mode. +// Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation); + m_followCamAuto = false; + if(!m_mouseLook) + { + if((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f)) + { + Vector3 camdif = new Vector3(1f, 0f, 0f) * Rotation; + float ftmp = camdif.X - CameraAtAxis.X; + if(Math.Abs(ftmp) < 0.1f) + { + ftmp = camdif.Y - CameraAtAxis.Y; + if(Math.Abs(ftmp) < 0.1f) + m_followCamAuto = true; + } + } + } if(agentData.NeedsCameraCollision) checkCameraCollision(); From 8dd9601fdcdaf77060446f40e69b3d1524afa31f Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 16 Nov 2016 00:42:08 +0000 Subject: [PATCH 050/305] minor change to getdisplaynames cap url --- .../Linden/Caps/GetDisplayNamesModule.cs | 7 ++- .../InstantMessage/InstantMessageModule.cs | 44 +------------------ 2 files changed, 5 insertions(+), 46 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs index eabacb42dd..bf559d3abe 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs @@ -120,14 +120,13 @@ namespace OpenSim.Region.ClientStack.Linden public virtual void RegisterCaps(UUID agentID, Caps caps) { - UUID capID = UUID.Random(); - if (m_URL == "localhost") { - m_log.DebugFormat("[GET_DISPLAY_NAMES]: /CAPS/agents/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); + string capUrl = "/CAPS/" + UUID.Random() + "/"; +// m_log.DebugFormat("[GET_DISPLAY_NAMES]: {0} in region {1}", capUrl, m_scene.RegionInfo.RegionName); caps.RegisterHandler( "GetDisplayNames", - new GetDisplayNamesHandler("/CAPS/agents" + capID + "/", m_UserManager, "GetDisplayNames", agentID.ToString())); + new GetDisplayNamesHandler(capUrl, m_UserManager, "GetDisplayNames", agentID.ToString())); } else { diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs index 2ba35df092..7d54a00c7f 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs @@ -45,10 +45,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - protected Timer m_logTimer = new Timer(10000); - protected List m_logData = new List(); - protected string m_restUrl; - /// /// Is this module enabled? /// @@ -68,12 +64,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage "InstantMessageModule", "InstantMessageModule") != "InstantMessageModule") return; - m_restUrl = config.Configs["Messaging"].GetString("LogURL", String.Empty); } m_enabled = true; - m_logTimer.AutoReset = false; - m_logTimer.Elapsed += LogTimerElapsed; } public virtual void AddRegion(Scene scene) @@ -153,20 +146,17 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage } #endregion - +/* public virtual void OnViewerInstantMessage(IClientAPI client, GridInstantMessage im) { im.fromAgentName = client.FirstName + " " + client.LastName; OnInstantMessage(client, im); } - +*/ public virtual void OnInstantMessage(IClientAPI client, GridInstantMessage im) { byte dialog = im.dialog; - if (client != null && dialog == (byte)InstantMessageDialog.MessageFromAgent) - LogInstantMesssage(im); - if (dialog != (byte)InstantMessageDialog.MessageFromAgent && dialog != (byte)InstantMessageDialog.StartTyping && dialog != (byte)InstantMessageDialog.StopTyping @@ -243,35 +233,5 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage // OnInstantMessage(null, msg); } - - protected virtual void LogInstantMesssage(GridInstantMessage im) - { - if (m_logData.Count < 20) - { - // Restart the log write timer - m_logTimer.Stop(); - } - if (!m_logTimer.Enabled) - m_logTimer.Start(); - - lock (m_logData) - { - m_logData.Add(im); - } - } - - protected virtual void LogTimerElapsed(object source, ElapsedEventArgs e) - { - lock (m_logData) - { - if (m_restUrl != String.Empty && m_logData.Count > 0) - { - bool success = SynchronousRestObjectRequester.MakeRequest, bool>("POST", m_restUrl + "/LogMessages/", m_logData); - if (!success) - m_log.ErrorFormat("[INSTANT MESSAGE]: Failed to save log data"); - } - m_logData.Clear(); - } - } } } From 05ba77fd3b72bb29a1f57245f8cd4ddeb6a19fb8 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 16 Nov 2016 03:47:48 +0000 Subject: [PATCH 051/305] fix parsing of a vector4 and storing on a lsl quaternion needed for lightShare scripts --- .../Shared/Api/Implementation/LS_Api.cs | 10 ++++---- .../Region/ScriptEngine/Shared/LSL_Types.cs | 25 +++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index e5e43f80fd..8cd065b36a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs @@ -295,7 +295,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api idx++; try { - iQ = rules.GetQuaternionItem(idx); + iQ = rules.GetVector4Item(idx); } catch (InvalidCastException) { @@ -319,7 +319,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api idx++; try { - iQ = rules.GetQuaternionItem(idx); + iQ = rules.GetVector4Item(idx); } catch (InvalidCastException) { @@ -342,7 +342,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api idx++; try { - iQ = rules.GetQuaternionItem(idx); + iQ = rules.GetVector4Item(idx); } catch (InvalidCastException) { @@ -532,7 +532,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api idx++; try { - iQ = rules.GetQuaternionItem(idx); + iQ = rules.GetVector4Item(idx); } catch (InvalidCastException) { @@ -654,7 +654,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; case (int)ScriptBaseClass.WL_SUN_MOON_COLOR: idx++; - iQ = rules.GetQuaternionItem(idx); + iQ = rules.GetVector4Item(idx); try { wl.sunMoonColor = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index c36e7c6c04..738a814602 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -700,6 +700,31 @@ namespace OpenSim.Region.ScriptEngine.Shared } } + // use LSL_Types.Quaternion to parse and store a vector4 for lightShare + public LSL_Types.Quaternion GetVector4Item(int itemIndex) + { + if (Data[itemIndex] is LSL_Types.Quaternion) + { + LSL_Types.Quaternion q = (LSL_Types.Quaternion)Data[itemIndex]; + return q; + } + else if(Data[itemIndex] is OpenMetaverse.Quaternion) + { + LSL_Types.Quaternion q = new LSL_Types.Quaternion( + (OpenMetaverse.Quaternion)Data[itemIndex]); + q.Normalize(); + return q; + } + else + { + throw new InvalidCastException(string.Format( + "{0} expected but {1} given", + typeof(LSL_Types.Quaternion).Name, + Data[itemIndex] != null ? + Data[itemIndex].GetType().Name : "null")); + } + } + public LSL_Types.Quaternion GetQuaternionItem(int itemIndex) { if (Data[itemIndex] is LSL_Types.Quaternion) From e77f91311678154390d09b586fbd8162cd3bb601 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 16 Nov 2016 22:34:56 +0000 Subject: [PATCH 052/305] minor: dont let rcvd agentupdates time jump back --- OpenSim/Framework/AgentUpdateArgs.cs | 1 + .../ClientStack/Linden/UDP/LLClientView.cs | 7 +++- .../Region/Framework/Scenes/ScenePresence.cs | 38 +++++++++++++------ 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/OpenSim/Framework/AgentUpdateArgs.cs b/OpenSim/Framework/AgentUpdateArgs.cs index eaa7902d8d..f04d692092 100644 --- a/OpenSim/Framework/AgentUpdateArgs.cs +++ b/OpenSim/Framework/AgentUpdateArgs.cs @@ -82,6 +82,7 @@ namespace OpenSim.Framework public Vector3 ClientAgentPosition; public bool UseClientAgentPosition; public bool NeedsCameraCollision; + public uint lastpacketSequence; public AgentUpdateArgs() { diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 46c6a19e9d..8d07bae155 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -6251,9 +6251,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP return false; } + uint seq = packet.Header.Sequence; + TotalAgentUpdates++; // dont let ignored updates pollute this throttles - if(SceneAgent == null || SceneAgent.IsChildAgent || SceneAgent.IsInTransit) + if(SceneAgent == null || SceneAgent.IsChildAgent || + SceneAgent.IsInTransit || seq <= m_thisAgentUpdateArgs.lastpacketSequence ) { // throttle reset is done at MoveAgentIntoRegion() // called by scenepresence on completemovement @@ -6261,6 +6264,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP return true; } + m_thisAgentUpdateArgs.lastpacketSequence = seq; + bool movement = CheckAgentMovementUpdateSignificance(x); bool camera = CheckAgentCameraUpdateSignificance(x); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 3378eade7c..f73d54e249 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2318,7 +2318,7 @@ namespace OpenSim.Region.Framework.Scenes Vector3 tocam = CameraPosition - posAdjusted; float distTocamlen = tocam.LengthSquared(); - if (distTocamlen > 0.08f && distTocamlen < 400) + if (distTocamlen > 0.01f && distTocamlen < 400) { distTocamlen = (float)Math.Sqrt(distTocamlen); tocam *= (1.0f / distTocamlen); @@ -4378,16 +4378,12 @@ namespace OpenSim.Region.Framework.Scenes m_log.DebugFormat( "[SCENE PRESENCE]: Closing child agents. Checking {0} regions in {1}", knownRegions.Count, Scene.RegionInfo.RegionName); - //DumpKnownRegions(); Util.RegionHandleToRegionLoc(newRegionHandle, out newRegionX, out newRegionY); uint x, y; spRegionSizeInfo regInfo; - // this should not be here - IEventQueue eventQueue = Scene.RequestModuleInterface(); - foreach (ulong handle in knownRegions) { // Don't close the agent on this region yet @@ -4400,16 +4396,10 @@ namespace OpenSim.Region.Framework.Scenes Util.RegionHandleToRegionLoc(handle, out x, out y); if (m_knownChildRegionsSizeInfo.TryGetValue(handle, out regInfo)) { - - // m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); - // m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); if (Util.IsOutsideView(RegionViewDistance, x, newRegionX, y, newRegionY, regInfo.sizeX, regInfo.sizeY, newRegionSizeX, newRegionSizeY)) { byebyeRegions.Add(handle); - // this should not be here -// if(eventQueue != null) -/// eventQueue.DisableSimulator(handle,UUID); } } else @@ -4445,6 +4435,32 @@ namespace OpenSim.Region.Framework.Scenes } } + public void closeAllChildAgents() + { + List byebyeRegions = new List(); + List knownRegions = KnownRegionHandles; + foreach (ulong handle in knownRegions) + { + if (handle != Scene.RegionInfo.RegionHandle) + { + byebyeRegions.Add(handle); + RemoveNeighbourRegion(handle); + Scene.CapsModule.DropChildSeed(UUID, handle); + } + } + + if (byebyeRegions.Count > 0) + { + m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); + + AgentCircuitData acd = Scene.AuthenticateHandler.GetAgentCircuitData(UUID); + string auth = string.Empty; + if (acd != null) + auth = acd.SessionID.ToString(); + m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions); + } + } + #endregion /// From 5645abf69c3a6951f87ff75854e0daefbe625e01 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 17 Nov 2016 00:13:21 +0000 Subject: [PATCH 053/305] fix a debug message --- OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs index 86fda36e81..38629b29d7 100644 --- a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs @@ -579,13 +579,13 @@ namespace OpenSim.Server.Handlers.Grid if (request.ContainsKey("SCOPEID")) UUID.TryParse(request["SCOPEID"].ToString(), out scopeID); else - m_log.WarnFormat("[GRID HANDLER]: no scopeID in request to get neighbours"); + m_log.WarnFormat("[GRID HANDLER]: no scopeID in request to get RegionFlags"); UUID regionID = UUID.Zero; if (request.ContainsKey("REGIONID")) UUID.TryParse(request["REGIONID"].ToString(), out regionID); else - m_log.WarnFormat("[GRID HANDLER]: no regionID in request to get neighbours"); + m_log.WarnFormat("[GRID HANDLER]: no regionID in request to get RegionFlags"); int flags = m_GridService.GetRegionFlags(scopeID, regionID); // m_log.DebugFormat("[GRID HANDLER]: flags for region {0}: {1}", regionID, flags); From 3d78388e55b056b92d97471ee79cfda87f710950 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 17 Nov 2016 01:44:47 +0000 Subject: [PATCH 054/305] restore large useracconts expire time for testing --- .../ServiceConnectorsOut/UserAccounts/UserAccountCache.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs index 6c1cc525b2..6d2efc6fa0 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs @@ -36,8 +36,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { public class UserAccountCache : IUserAccountCacheModule { - private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour! - private const double CACHE_NULL_EXPIRATION_SECONDS = 600; // 10minutes +// private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour! +// private const double CACHE_NULL_EXPIRATION_SECONDS = 600; // 10minutes + private const double CACHE_EXPIRATION_SECONDS = 120000.0; + private const double CACHE_NULL_EXPIRATION_SECONDS = 120000.0; // private static readonly ILog m_log = // LogManager.GetLogger( From 2db22bf064f14afcbfecacfb8006da5c44a6040c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 17 Nov 2016 13:57:45 +0000 Subject: [PATCH 055/305] minor changes to ubMeshmerizer memory use --- .../PhysicsModules/ubOdeMeshing/Mesh.cs | 129 +++++++++--------- .../ubOdeMeshing/Meshmerizer.cs | 4 +- 2 files changed, 66 insertions(+), 67 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Mesh.cs b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Mesh.cs index d9ea4a4991..0cdaa60c15 100644 --- a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Mesh.cs +++ b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Mesh.cs @@ -39,6 +39,24 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing { public class MeshBuildingData { + private class vertexcomp : IEqualityComparer + { + public bool Equals(Vertex v1, Vertex v2) + { + if (v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z) + return true; + else + return false; + } + public int GetHashCode(Vertex v) + { + int a = v.X.GetHashCode(); + int b = v.Y.GetHashCode(); + int c = v.Z.GetHashCode(); + return (a << 16) ^ (b << 8) ^ c; + } + } + public Dictionary m_vertices; public List m_triangles; public float m_obbXmin; @@ -49,6 +67,21 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing public float m_obbZmax; public Vector3 m_centroid; public int m_centroidDiv; + + public MeshBuildingData() + { + vertexcomp vcomp = new vertexcomp(); + m_vertices = new Dictionary(vcomp); + m_triangles = new List(); + m_centroid = Vector3.Zero; + m_centroidDiv = 0; + m_obbXmin = float.MaxValue; + m_obbXmax = float.MinValue; + m_obbYmin = float.MaxValue; + m_obbYmax = float.MinValue; + m_obbZmin = float.MaxValue; + m_obbZmax = float.MinValue; + } } [Serializable()] @@ -76,50 +109,20 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing public int RefCount { get; set; } public AMeshKey Key { get; set; } - private class vertexcomp : IEqualityComparer + public Mesh(bool forbuild) { - public bool Equals(Vertex v1, Vertex v2) - { - if (v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z) - return true; - else - return false; - } - public int GetHashCode(Vertex v) - { - int a = v.X.GetHashCode(); - int b = v.Y.GetHashCode(); - int c = v.Z.GetHashCode(); - return (a << 16) ^ (b << 8) ^ c; - } - } - - public Mesh() - { - vertexcomp vcomp = new vertexcomp(); - - m_bdata = new MeshBuildingData(); - m_bdata.m_vertices = new Dictionary(vcomp); - m_bdata.m_triangles = new List(); - m_bdata.m_centroid = Vector3.Zero; - m_bdata.m_centroidDiv = 0; - m_bdata.m_obbXmin = float.MaxValue; - m_bdata.m_obbXmax = float.MinValue; - m_bdata.m_obbYmin = float.MaxValue; - m_bdata.m_obbYmax = float.MinValue; - m_bdata.m_obbZmin = float.MaxValue; - m_bdata.m_obbZmax = float.MinValue; + if(forbuild) + m_bdata = new MeshBuildingData(); m_obb = new Vector3(0.5f, 0.5f, 0.5f); m_obboffset = Vector3.Zero; } - public Mesh Scale(Vector3 scale) { if (m_verticesPtr == null || m_indicesPtr == null) return null; - Mesh result = new Mesh(); + Mesh result = new Mesh(false); float x = scale.X; float y = scale.Y; @@ -167,7 +170,7 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing public Mesh Clone() { - Mesh result = new Mesh(); + Mesh result = new Mesh(false); if (m_bdata != null) { @@ -514,8 +517,6 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing if (m_indicesPtr == IntPtr.Zero) indexes = getIndexListAsInt(); - pinMemory(); - float x, y, z; if (m_bdata.m_centroidDiv > 0) @@ -543,55 +544,53 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing m_obb = new Vector3(x, y, z); releaseBuildingMeshData(); + pinMemory(); } + public bool ToStream(Stream st) { if (m_indicesPtr == IntPtr.Zero || m_verticesPtr == IntPtr.Zero) return false; - BinaryWriter bw = new BinaryWriter(st); bool ok = true; try { + using(BinaryWriter bw = new BinaryWriter(st)) + { + bw.Write(m_vertexCount); + bw.Write(m_indexCount); - bw.Write(m_vertexCount); - bw.Write(m_indexCount); - - for (int i = 0; i < 3 * m_vertexCount; i++) - bw.Write(vertices[i]); - for (int i = 0; i < m_indexCount; i++) - bw.Write(indexes[i]); - bw.Write(m_obb.X); - bw.Write(m_obb.Y); - bw.Write(m_obb.Z); - bw.Write(m_obboffset.X); - bw.Write(m_obboffset.Y); - bw.Write(m_obboffset.Z); + for (int i = 0; i < 3 * m_vertexCount; i++) + bw.Write(vertices[i]); + for (int i = 0; i < m_indexCount; i++) + bw.Write(indexes[i]); + bw.Write(m_obb.X); + bw.Write(m_obb.Y); + bw.Write(m_obb.Z); + bw.Write(m_obboffset.X); + bw.Write(m_obboffset.Y); + bw.Write(m_obboffset.Z); + bw.Flush(); + bw.Close(); + } } catch { ok = false; } - if (bw != null) - { - bw.Flush(); - bw.Close(); - } - return ok; } public static Mesh FromStream(Stream st, AMeshKey key) { - Mesh mesh = new Mesh(); - mesh.releaseBuildingMeshData(); + Mesh mesh = new Mesh(false); bool ok = true; - using(BinaryReader br = new BinaryReader(st)) + try { - try + using(BinaryReader br = new BinaryReader(st)) { mesh.m_vertexCount = br.ReadInt32(); mesh.m_indexCount = br.ReadInt32(); @@ -613,10 +612,10 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing mesh.m_obboffset.Y = br.ReadSingle(); mesh.m_obboffset.Z = br.ReadSingle(); } - catch - { - ok = false; - } + } + catch + { + ok = false; } if (ok) diff --git a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs index ca94034b10..98c2e71caf 100644 --- a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs +++ b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs @@ -182,7 +182,7 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing /// private static Mesh CreateSimpleBoxMesh(float minX, float maxX, float minY, float maxY, float minZ, float maxZ) { - Mesh box = new Mesh(); + Mesh box = new Mesh(true); List vertices = new List(); // bottom @@ -357,7 +357,7 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing int numCoords = coords.Count; int numFaces = faces.Count; - Mesh mesh = new Mesh(); + Mesh mesh = new Mesh(true); // Add the corresponding triangles to the mesh for (int i = 0; i < numFaces; i++) { From 8599a9a1cae6dc7a0760448b4ac8e9a773348c1e Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 17 Nov 2016 17:37:22 +0000 Subject: [PATCH 056/305] add a missing dispose --- OpenSim/Framework/TaskInventoryDictionary.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/OpenSim/Framework/TaskInventoryDictionary.cs b/OpenSim/Framework/TaskInventoryDictionary.cs index 2c20ef7719..c270d98ee7 100644 --- a/OpenSim/Framework/TaskInventoryDictionary.cs +++ b/OpenSim/Framework/TaskInventoryDictionary.cs @@ -64,6 +64,13 @@ namespace OpenSim.Framework /// private volatile System.Threading.ReaderWriterLockSlim m_itemLock = new System.Threading.ReaderWriterLockSlim(); + + ~TaskInventoryDictionary() + { + m_itemLock.Dispose(); + m_itemLock = null; + } + /// /// Are we readlocked by the calling thread? /// From 35b37510fca537d12c2eabc68be51e370dc6d6ce Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 17 Nov 2016 19:15:28 +0000 Subject: [PATCH 057/305] explicitly remove some references, and other useless changes --- OpenSim/Framework/WebUtil.cs | 8 +- .../ClientStack/Linden/UDP/LLClientView.cs | 160 +++++++++--------- .../ClientStack/Linden/UDP/LLUDPClient.cs | 22 ++- .../Linden/UDP/UnackedPacketCollection.cs | 9 + .../Region/Framework/Scenes/ScenePresence.cs | 24 ++- 5 files changed, 126 insertions(+), 97 deletions(-) diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 51d87bdf2d..2bbf785661 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -1062,11 +1062,10 @@ namespace OpenSim.Framework if (WebUtil.DebugLevel >= 5) WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data)); - Stream requestStream = null; try { - requestStream = request.GetRequestStream(); - requestStream.Write(data, 0, length); + using(Stream requestStream = request.GetRequestStream()) + requestStream.Write(data,0,length); } catch (Exception e) { @@ -1076,9 +1075,6 @@ namespace OpenSim.Framework } finally { - if (requestStream != null) - requestStream.Dispose(); - // capture how much time was spent writing tickdata = Util.EnvironmentTickCountSubtract(tickstart); } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 8d07bae155..37937123b4 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -346,12 +346,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP private bool m_VelocityInterpolate = false; private const uint MaxTransferBytesPerPacket = 600; - /// - /// List used in construction of data blocks for an object update packet. This is to stop us having to - /// continually recreate it. - /// - protected List m_fullUpdateDataBlocksBuilder; - /// /// Maintain a record of all the objects killed. This allows us to stop an update being sent from the /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an @@ -511,7 +505,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_scene = scene; m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); m_entityProps = new PriorityQueue(m_scene.Entities.Count); - m_fullUpdateDataBlocksBuilder = new List(); m_killRecord = new List(); // m_attachmentsSent = new HashSet(); @@ -594,13 +587,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(disable, ThrottleOutPacketType.Unknown); } - // Shutdown the image manager - ImageManager.Close(); // Fire the callback for this connection closing if (OnConnectionClosed != null) OnConnectionClosed(this); + // Flush all of the packets out of the UDP server for this client if (m_udpServer != null) m_udpServer.Flush(m_udpClient); @@ -615,8 +607,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Disable UDP handling for this client m_udpClient.Shutdown(); - - + + m_udpClient.OnQueueEmpty -= HandleQueueEmpty; + m_udpClient.HasUpdates -= HandleHasUpdates; + m_udpClient.OnPacketStats -= PopulateStats; + + // Shutdown the image manager + ImageManager.Close(); + ImageManager = null; + + m_entityUpdates = null; + m_entityProps = null; + m_killRecord.Clear(); + GroupsInView.Clear(); + m_scene = null; //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); //GC.Collect(); //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); @@ -814,7 +818,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void ProcessSpecificPacketAsync(object state) { AsyncPacketProcess packetObject = (AsyncPacketProcess)state; - + try { packetObject.result = packetObject.Method(packetObject.ClientView, packetObject.Pack); @@ -4095,19 +4099,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP ResendPrimUpdate(update); } + private List objectUpdateBlocks = new List(); + private List compressedUpdateBlocks = new List(); + private List terseUpdateBlocks = new List(); + private List terseAgentUpdateBlocks = new List(); + private void ProcessEntityUpdates(int maxUpdatesBytes) { - OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); - OpenSim.Framework.Lazy> compressedUpdateBlocks = new OpenSim.Framework.Lazy>(); - OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>(); - OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>(); - OpenSim.Framework.Lazy> objectUpdates = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> compressedUpdates = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseUpdates = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseAgentUpdates = new OpenSim.Framework.Lazy>(); - // Check to see if this is a flush if (maxUpdatesBytes <= 0) { @@ -4328,7 +4331,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP ablock = CreateAvatarUpdateBlock((ScenePresence)update.Entity); else ablock = CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId); - objectUpdateBlocks.Value.Add(ablock); + objectUpdateBlocks.Add(ablock); objectUpdates.Value.Add(update); maxUpdatesBytes -= ablock.Length; @@ -4337,7 +4340,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { ObjectUpdateCompressedPacket.ObjectDataBlock ablock = CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags); - compressedUpdateBlocks.Value.Add(ablock); + compressedUpdateBlocks.Add(ablock); compressedUpdates.Value.Add(update); maxUpdatesBytes -= ablock.Length; } @@ -4348,14 +4351,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP { // ALL presence updates go into a special list ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)); - terseAgentUpdateBlocks.Value.Add(ablock); + terseAgentUpdateBlocks.Add(ablock); terseAgentUpdates.Value.Add(update); } else { // Everything else goes here ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)); - terseUpdateBlocks.Value.Add(ablock); + terseUpdateBlocks.Add(ablock); terseUpdates.Value.Add(update); } maxUpdatesBytes -= ablock.Length; @@ -4366,74 +4369,69 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Packet Sending -// const float TIME_DILATION = 1.0f; ushort timeDilation; -// if(updatesThisCall > 0) -// timeDilation = Utils.FloatToUInt16(avgTimeDilation/updatesThisCall, 0.0f, 1.0f); -// else -// timeDilation = ushort.MaxValue; // 1.0; timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); - if (terseAgentUpdateBlocks.IsValueCreated) + if (terseAgentUpdateBlocks.Count > 0) { - List blocks = terseAgentUpdateBlocks.Value; - ImprovedTerseObjectUpdatePacket packet = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; + packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseAgentUpdateBlocks.Count]; - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; + for (int i = 0; i < terseAgentUpdateBlocks.Count; i++) + packet.ObjectData[i] = terseAgentUpdateBlocks[i]; + + terseAgentUpdateBlocks.Clear(); OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); } - if (objectUpdateBlocks.IsValueCreated) + if (objectUpdateBlocks.Count > 0) { - List blocks = objectUpdateBlocks.Value; - ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; + packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[objectUpdateBlocks.Count]; - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; + for (int i = 0; i < objectUpdateBlocks.Count; i++) + packet.ObjectData[i] = objectUpdateBlocks[i]; + + objectUpdateBlocks.Clear(); OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); }); } - if (compressedUpdateBlocks.IsValueCreated) + if (compressedUpdateBlocks.Count > 0) { - List blocks = compressedUpdateBlocks.Value; - ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed); packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count]; + packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[compressedUpdateBlocks.Count]; - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; + for (int i = 0; i < compressedUpdateBlocks.Count; i++) + packet.ObjectData[i] = compressedUpdateBlocks[i]; + + compressedUpdateBlocks.Clear(); OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); }); } - if (terseUpdateBlocks.IsValueCreated) + if (terseUpdateBlocks.Count > 0) { - List blocks = terseUpdateBlocks.Value; - ImprovedTerseObjectUpdatePacket packet = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( PacketType.ImprovedTerseObjectUpdate); packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; + packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseUpdateBlocks.Count]; - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; + for (int i = 0; i < terseUpdateBlocks.Count; i++) + packet.ObjectData[i] = terseUpdateBlocks[i]; + + terseUpdateBlocks.Clear(); OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); } @@ -4828,21 +4826,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); } + List objectFamilyBlocks = new + List(); + List objectPropertiesBlocks = + new List(); + List needPhysics = new List(); + private void ProcessEntityPropertyRequests(int maxUpdateBytes) { - OpenSim.Framework.Lazy> objectFamilyBlocks = - new OpenSim.Framework.Lazy>(); +// OpenSim.Framework.Lazy> familyUpdates = +// new OpenSim.Framework.Lazy>(); - OpenSim.Framework.Lazy> objectPropertiesBlocks = - new OpenSim.Framework.Lazy>(); - - OpenSim.Framework.Lazy> familyUpdates = - new OpenSim.Framework.Lazy>(); - - OpenSim.Framework.Lazy> propertyUpdates = - new OpenSim.Framework.Lazy>(); +// OpenSim.Framework.Lazy> propertyUpdates = +// new OpenSim.Framework.Lazy>(); - List needPhysics = new List(); EntityUpdate iupdate; Int32 timeinqueue; // this is just debugging code & can be dropped later @@ -4860,8 +4857,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP { SceneObjectPart sop = (SceneObjectPart)update.Entity; ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); - objectFamilyBlocks.Value.Add(objPropDB); - familyUpdates.Value.Add(update); + objectFamilyBlocks.Add(objPropDB); +// familyUpdates.Value.Add(update); maxUpdateBytes -= objPropDB.Length; } } @@ -4873,23 +4870,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP SceneObjectPart sop = (SceneObjectPart)update.Entity; needPhysics.Add(sop); ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); - objectPropertiesBlocks.Value.Add(objPropDB); - propertyUpdates.Value.Add(update); + objectPropertiesBlocks.Add(objPropDB); +// propertyUpdates.Value.Add(update); maxUpdateBytes -= objPropDB.Length; } } } - if (objectPropertiesBlocks.IsValueCreated) + if (objectPropertiesBlocks.Count > 0) { - List blocks = objectPropertiesBlocks.Value; - List updates = propertyUpdates.Value; - ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); - packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; + packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[objectPropertiesBlocks.Count]; + for (int i = 0; i < objectPropertiesBlocks.Count; i++) + packet.ObjectData[i] = objectPropertiesBlocks[i]; + + objectPropertiesBlocks.Clear(); packet.Header.Zerocoded = true; // Pass in the delegate so that if this packet needs to be resent, we send the current properties @@ -4898,7 +4894,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP //OutPacket(packet, ThrottleOutPacketType.Task, true, // delegate(OutgoingPacket oPacket) // { - // ResendPropertyUpdates(updates, oPacket); + // ResendPropertyUpdates(propertyUpdates.Value, oPacket); // }); OutPacket(packet, ThrottleOutPacketType.Task, true); @@ -4909,23 +4905,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Int32 fpcnt = 0; // Int32 fbcnt = 0; - if (objectFamilyBlocks.IsValueCreated) - { - List blocks = objectFamilyBlocks.Value; - + if (objectFamilyBlocks.Count > 0) + { // one packet per object block... uggh... - for (int i = 0; i < blocks.Count; i++) + for (int i = 0; i < objectFamilyBlocks.Count; i++) { ObjectPropertiesFamilyPacket packet = (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); - packet.ObjectData = blocks[i]; + packet.ObjectData = objectFamilyBlocks[i]; packet.Header.Zerocoded = true; // Pass in the delegate so that if this packet needs to be resent, we send the current properties // of the object rather than the properties when the packet was created - List updates = new List(); - updates.Add(familyUpdates.Value[i]); +// List updates = new List(); +// updates.Add(familyUpdates.Value[i]); // HACK : Remove intelligent resending until it's fixed in core //OutPacket(packet, ThrottleOutPacketType.Task, true, // delegate(OutgoingPacket oPacket) @@ -4937,6 +4931,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // fpcnt++; // fbcnt++; } + objectFamilyBlocks.Clear(); } if(needPhysics.Count > 0) @@ -4962,6 +4957,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP eq.Enqueue(BuildEvent("ObjectPhysicsProperties", llsdBody),AgentId); } + needPhysics.Clear(); } // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index d59b7614ed..e85cee2524 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -120,13 +120,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Circuit code that this client is connected on public readonly uint CircuitCode; /// Sequence numbers of packets we've received (for duplicate checking) - public readonly IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200); + public IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200); /// Packets we have sent that need to be ACKed by the client - public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); + public UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); /// ACKs that are queued up, waiting to be sent to the client - public readonly DoubleLocklessQueue PendingAcks = new DoubleLocklessQueue(); + public DoubleLocklessQueue PendingAcks = new DoubleLocklessQueue(); /// Current packet sequence number public int CurrentSequence; @@ -170,7 +170,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private double m_nextOnQueueEmpty = 0; /// Throttle bucket for this agent's connection - private readonly AdaptiveTokenBucket m_throttleClient; + private AdaptiveTokenBucket m_throttleClient; public AdaptiveTokenBucket FlowThrottle { get { return m_throttleClient; } @@ -179,10 +179,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Throttle buckets for each packet category private readonly TokenBucket[] m_throttleCategories; /// Outgoing queues for throttled packets - private readonly DoubleLocklessQueue[] m_packetOutboxes = new DoubleLocklessQueue[THROTTLE_CATEGORY_COUNT]; + private DoubleLocklessQueue[] m_packetOutboxes = new DoubleLocklessQueue[THROTTLE_CATEGORY_COUNT]; /// A container that can hold one packet for each outbox, used to store /// dequeued packets that are being held for throttling - private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; + private OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; /// A reference to the LLUDPServer that is managing this client private readonly LLUDPServer m_udpServer; @@ -288,14 +288,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) { m_packetOutboxes[i].Clear(); + m_throttleCategories[i] = null; m_nextPackets[i] = null; } // pull the throttle out of the scene throttle m_throttleClient.Parent.UnregisterRequest(m_throttleClient); + m_throttleClient = null; OnPacketStats = null; OnQueueEmpty = null; - } + PendingAcks.Clear(); + NeedAcks.Clear(); + NeedAcks = null; + PendingAcks = null; + m_nextPackets = null; + m_packetOutboxes = null; + } /// /// Gets information about this client connection diff --git a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs index b546a99603..c9d5697b23 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs @@ -74,6 +74,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Holds information about pending removals private LocklessQueue m_pendingRemoves = new LocklessQueue(); + + public void Clear() + { + m_packets.Clear(); + m_pendingAdds = null; + m_pendingAcknowledgements = null; + m_pendingRemoves = null; + } + /// /// Add an unacked packet to the collection /// diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index f73d54e249..2cfdd946f9 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1104,7 +1104,7 @@ namespace OpenSim.Region.Framework.Scenes AdjustKnownSeeds(); - RegisterToEvents(); + RegisterToClientEvents(); SetDirectionVectors(); Appearance = appearance; @@ -1171,7 +1171,7 @@ namespace OpenSim.Region.Framework.Scenes } } - public void RegisterToEvents() + public void RegisterToClientEvents() { ControllingClient.OnCompleteMovementToRegion += CompleteMovement; ControllingClient.OnAgentUpdate += HandleAgentUpdate; @@ -1189,6 +1189,22 @@ namespace OpenSim.Region.Framework.Scenes // ControllingClient.OnChildAgentStatus += new StatusChange(this.ChildStatusChange); // ControllingClient.OnStopMovement += new GenericCall2(this.StopMovement); } + + public void RemoveClientEvents() + { + ControllingClient.OnCompleteMovementToRegion -= CompleteMovement; + ControllingClient.OnAgentUpdate -= HandleAgentUpdate; + ControllingClient.OnAgentCameraUpdate -= HandleAgentCamerasUpdate; + ControllingClient.OnAgentRequestSit -= HandleAgentRequestSit; + ControllingClient.OnAgentSit -= HandleAgentSit; + ControllingClient.OnSetAlwaysRun -= HandleSetAlwaysRun; + ControllingClient.OnStartAnim -= HandleStartAnim; + ControllingClient.OnStopAnim -= HandleStopAnim; + ControllingClient.OnChangeAnim -= avnHandleChangeAnim; + ControllingClient.OnForceReleaseControls -= HandleForceReleaseControls; + ControllingClient.OnAutoPilotGo -= MoveToTarget; + ControllingClient.OnUpdateThrottles -= RaiseUpdateThrottles; + } private void SetDirectionVectors() { @@ -5016,12 +5032,16 @@ namespace OpenSim.Region.Framework.Scenes RemoveFromPhysicalScene(); m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; + RemoveClientEvents(); // if (Animator != null) // Animator.Close(); Animator = null; + scriptedcontrols.Clear(); + ControllingClient = null; LifecycleState = ScenePresenceState.Removed; + IsDeleted = true; } public void AddAttachment(SceneObjectGroup gobj) From e21ac8b3c40665449e8dc1bbc5647b93c1a59f6c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 17 Nov 2016 20:59:13 +0000 Subject: [PATCH 058/305] counting issus safeguard --- OpenSim/Framework/LocklessQueue.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/LocklessQueue.cs b/OpenSim/Framework/LocklessQueue.cs index 9bd9baf321..7ccbba7b55 100644 --- a/OpenSim/Framework/LocklessQueue.cs +++ b/OpenSim/Framework/LocklessQueue.cs @@ -93,7 +93,10 @@ namespace OpenSim.Framework if (oldHead == oldTail) { if (oldHeadNext == null) + { + count = 0; return false; + } CAS(ref tail, oldTail, oldHeadNext); } @@ -118,8 +121,7 @@ namespace OpenSim.Framework { // ugly T item; - while(count > 0) - Dequeue(out item); + while(Dequeue(out item)); Init(); } From ba7904a3a80713f726d434fc82e9a80306372e2c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 18 Nov 2016 00:12:09 +0000 Subject: [PATCH 059/305] a few more changes on potencial mem issues --- OpenSim/Capabilities/Caps.cs | 5 +++++ OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs | 5 +++++ .../Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs | 10 ++++++++-- ThirdParty/SmartThreadPool/WorkItemsQueue.cs | 1 + 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs index 3efab8e7ec..5e89c388f4 100644 --- a/OpenSim/Capabilities/Caps.cs +++ b/OpenSim/Capabilities/Caps.cs @@ -141,6 +141,11 @@ namespace OpenSim.Framework.Capabilities m_capsActive.Reset(); } + ~Caps() + { + m_capsActive.Dispose(); + } + /// /// Register a handler. This allows modules to register handlers. /// diff --git a/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs index 9056548a51..4ff8cbabfa 100644 --- a/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs +++ b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs @@ -55,6 +55,11 @@ namespace OpenSim.Framework Dictionary2 = new Dictionary(capacity); } + ~DoubleDictionaryThreadAbortSafe() + { + rwLock.Dispose(); + } + public void Add(TKey1 key1, TKey2 key2, TValue value) { bool gotLock = false; diff --git a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs index 98c2e71caf..2ae0881e78 100644 --- a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs +++ b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs @@ -1483,6 +1483,7 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing lock (diskLock) { + Stream stream = null; try { if (!Directory.Exists(dir)) @@ -1490,8 +1491,8 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing Directory.CreateDirectory(dir); } - using(Stream stream = File.Open(filename, FileMode.Create)) - ok = mesh.ToStream(stream); + stream = File.Open(filename, FileMode.Create); + ok = mesh.ToStream(stream); } catch (IOException e) { @@ -1500,6 +1501,11 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing filename, e.Message, e.StackTrace); ok = false; } + finally + { + if(stream != null) + stream.Dispose(); + } if (!ok && File.Exists(filename)) { diff --git a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs index e0bc9168ec..019c0d34b2 100644 --- a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs +++ b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs @@ -625,6 +625,7 @@ namespace Amib.Threading.Internal if (!_isDisposed) { Cleanup(); + _headWaiterEntry.Close(); } _isDisposed = true; } From 0a8cf2ff08a958154fd8f9f73ad31b9aba00e8b9 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 18 Nov 2016 02:13:01 +0000 Subject: [PATCH 060/305] put back skip of first drip call --- OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs index 7b9661b80c..d4603f80a5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs @@ -193,7 +193,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP Parent = parent; RequestedDripRate = dripRate; RequestedBurst = MaxBurst; - m_lastDrip = Util.GetTimeStampMS() + 50.0; + m_lastDrip = Util.GetTimeStampMS() + 100000.0; // skip first drip } #endregion Constructor From d8812ba2d1a82bf2e6c945544cb72a6412ef48ae Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 18 Nov 2016 03:00:59 +0000 Subject: [PATCH 061/305] revert to lower resolution clock on udpserver for testing --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index ffdb6398a9..b491110fd8 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -323,7 +323,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected int m_elapsedMSSinceLastStatReport = 0; /// Environment.TickCount of the last time the outgoing packet handler executed - protected double m_tickLastOutgoingPacketHandler; + protected int m_tickLastOutgoingPacketHandler; /// Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped protected int m_elapsedMSOutgoingPacketHandler; @@ -2073,13 +2073,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_sendPing = false; // Update elapsed time - double thisTick = Util.GetTimeStampMS(); - int deltaMS = (int)(thisTick - m_tickLastOutgoingPacketHandler); + int thisTick = Environment.TickCount & Int32.MaxValue; + if (m_tickLastOutgoingPacketHandler > thisTick) + m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick); + else + m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler); + m_tickLastOutgoingPacketHandler = thisTick; // update some 1ms resolution chained timers - - m_elapsedMSOutgoingPacketHandler += deltaMS; // Check for pending outgoing resends every 100ms if (m_elapsedMSOutgoingPacketHandler >= 100) From e281876ecdb5edff737556c7200b8a902e66d05e Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 18 Nov 2016 03:25:29 +0000 Subject: [PATCH 062/305] restore higher resolution clock on udpserver and lower uaeraccouts caching time --- .../ClientStack/Linden/UDP/LLUDPServer.cs | 18 +++++++----------- .../UserAccounts/UserAccountCache.cs | 6 ++---- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index b491110fd8..af33d17b7e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -323,10 +323,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected int m_elapsedMSSinceLastStatReport = 0; /// Environment.TickCount of the last time the outgoing packet handler executed - protected int m_tickLastOutgoingPacketHandler; + protected double m_tickLastOutgoingPacketHandler; /// Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped - protected int m_elapsedMSOutgoingPacketHandler; + protected double m_elapsedMSOutgoingPacketHandler; /// Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed protected int m_elapsed100MSOutgoingPacketHandler; @@ -2073,21 +2073,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_sendPing = false; // Update elapsed time - int thisTick = Environment.TickCount & Int32.MaxValue; - if (m_tickLastOutgoingPacketHandler > thisTick) - m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick); - else - m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler); - - m_tickLastOutgoingPacketHandler = thisTick; + double thisTick = Util.GetTimeStampMS(); // update some 1ms resolution chained timers + m_elapsedMSOutgoingPacketHandler += thisTick - m_tickLastOutgoingPacketHandler; + m_tickLastOutgoingPacketHandler = thisTick; // Check for pending outgoing resends every 100ms - if (m_elapsedMSOutgoingPacketHandler >= 100) + if (m_elapsedMSOutgoingPacketHandler >= 100.0) { m_resendUnacked = true; - m_elapsedMSOutgoingPacketHandler = 0; + m_elapsedMSOutgoingPacketHandler = 0.0; m_elapsed100MSOutgoingPacketHandler += 1; } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs index 6d2efc6fa0..6c1cc525b2 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs @@ -36,10 +36,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { public class UserAccountCache : IUserAccountCacheModule { -// private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour! -// private const double CACHE_NULL_EXPIRATION_SECONDS = 600; // 10minutes - private const double CACHE_EXPIRATION_SECONDS = 120000.0; - private const double CACHE_NULL_EXPIRATION_SECONDS = 120000.0; + private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour! + private const double CACHE_NULL_EXPIRATION_SECONDS = 600; // 10minutes // private static readonly ILog m_log = // LogManager.GetLogger( From 70eb37433d4cc7512ebe6cac1d7c288c9b1db06f Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 18 Nov 2016 03:40:34 +0000 Subject: [PATCH 063/305] avoid a null ref. (needs better way) --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 37937123b4..8ba26e83f9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -4371,6 +4371,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP ushort timeDilation; + if(m_scene == null) + return; + timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); if (terseAgentUpdateBlocks.Count > 0) @@ -4632,6 +4635,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) { + if(m_scene == null) + return; + if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) { int maxUpdateBytes = m_udpClient.GetCatBytesCanSend(ThrottleOutPacketType.Task, 30); From b43f36abf168a0cce7e71178e3d4766a717c7d60 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 18 Nov 2016 15:16:11 +0000 Subject: [PATCH 064/305] add expire time for aliens --- .../UserAccounts/UserAccountCache.cs | 33 +++++++++++++++---- .../Interfaces/IUserAccountCacheModule.cs | 2 ++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs index 6c1cc525b2..2afd74e36e 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs @@ -36,6 +36,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { public class UserAccountCache : IUserAccountCacheModule { + private const double CACHE_ALIEN_EXPIRATION_SECONDS = 172800; // 48 hours private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour! private const double CACHE_NULL_EXPIRATION_SECONDS = 600; // 10minutes @@ -60,21 +61,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { if (account == null) m_UUIDCache.AddOrUpdate(userID, null, CACHE_NULL_EXPIRATION_SECONDS); - else + else if(account.LocalToGrid) { m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS); m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_EXPIRATION_SECONDS); } - + else + { + m_UUIDCache.AddOrUpdate(userID, account, CACHE_ALIEN_EXPIRATION_SECONDS); + m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_ALIEN_EXPIRATION_SECONDS); + } //m_log.DebugFormat("[USER CACHE]: cached user {0}", userID); } } - public void Invalidate(UUID userID) - { - lock(accessLock) - m_UUIDCache.Remove(userID); - } public UserAccount Get(UUID userID, out bool inCache) { @@ -114,6 +114,25 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts return null; } + public void Invalidate(UUID userID) + { + m_UUIDCache.Remove(userID); + } + + public void Remove(UUID id) + { + lock(accessLock) + { + if (!m_UUIDCache.Contains(id)) + return; + + UserAccount account = null; + if (m_UUIDCache.TryGetValue(id, out account) && account != null) + m_NameCache.Remove(account.Name); + m_UUIDCache.Remove(id); + } + } + public void Remove(string name) { lock(accessLock) diff --git a/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs b/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs index ed269896a9..027a7e2e5a 100644 --- a/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs @@ -26,8 +26,10 @@ */ using OpenSim.Region.Framework.Scenes; +using OpenMetaverse; public interface IUserAccountCacheModule { void Remove(string name); + void Remove(UUID id); } From 1396c466f65de8c1963282e7d59d3fb2acbbfe84 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 18 Nov 2016 17:30:15 +0000 Subject: [PATCH 065/305] search accout by id not volatil user name (HG) --- OpenSim/Region/Framework/Scenes/Scene.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index ca32940cd2..c349369604 100755 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4141,7 +4141,8 @@ namespace OpenSim.Region.Framework.Scenes { IUserAccountCacheModule cache = RequestModuleInterface(); if (cache != null) - cache.Remove(acd.firstname + " " + acd.lastname); +// cache.Remove(acd.firstname + " " + acd.lastname); + cache.Remove(acd.AgentID); // Remove any preexisting circuit - we don't want duplicates // This is a stab at preventing avatar "ghosting" From 6749c61d4fc064a954807c9f24284542a2159cd2 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Fri, 11 Nov 2016 17:31:46 +0000 Subject: [PATCH 066/305] Fix the previous commit --- .../PasswordAuthenticationService.cs | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs index 2e8ffe5aae..a9359f3cd0 100644 --- a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs +++ b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs @@ -72,8 +72,11 @@ namespace OpenSim.Services.AuthenticationService { realID = UUID.Zero; - m_log.DebugFormat("[AUTH SERVICE]: Authenticating for {0}", principalID); + m_log.DebugFormat("[AUTH SERVICE]: Authenticating for {0}, user account service present: {1}", principalID, m_UserAccountService != null); AuthenticationData data = m_Database.Get(principalID); + UserAccount user = null; + if (m_UserAccountService != null) + user = m_UserAccountService.GetUserAccount(UUID.Zero, principalID); if (data == null || data.Data == null) { @@ -97,7 +100,53 @@ namespace OpenSim.Services.AuthenticationService return GetToken(principalID, lifetime); } - m_log.DebugFormat("[AUTH SERVICE]: Authenticating FAIL for {0} ", principalID); + if (user == null) + { + m_log.DebugFormat("[PASS AUTH]: No user record for {0}", principalID); + return String.Empty; + } + + int impersonateFlag = 1 << 6; + + if ((user.UserFlags & impersonateFlag) == 0) + return String.Empty; + + m_log.DebugFormat("[PASS AUTH]: Attempting impersonation"); + + List accounts = m_UserAccountService.GetUserAccountsWhere(UUID.Zero, "UserLevel >= 200"); + if (accounts == null || accounts.Count == 0) + return String.Empty; + + foreach (UserAccount a in accounts) + { + data = m_Database.Get(a.PrincipalID); + if (data == null || data.Data == null || + !data.Data.ContainsKey("passwordHash") || + !data.Data.ContainsKey("passwordSalt")) + { + continue; + } + +// m_log.DebugFormat("[PASS AUTH]: Trying {0}", data.PrincipalID); + + hashed = Util.Md5Hash(password + ":" + + data.Data["passwordSalt"].ToString()); + + if (data.Data["passwordHash"].ToString() == hashed) + { + m_log.DebugFormat("[PASS AUTH]: {0} {1} impersonating {2}, proceeding with login", a.FirstName, a.LastName, principalID); + realID = a.PrincipalID; + return GetToken(principalID, lifetime); + } +// else +// { +// m_log.DebugFormat( +// "[AUTH SERVICE]: Salted hash {0} of given password did not match salted hash of {1} for PrincipalID {2}. Authentication failure.", +// hashed, data.Data["passwordHash"], data.PrincipalID); +// } + } + + m_log.DebugFormat("[PASS AUTH]: Impersonation of {0} failed", principalID); return String.Empty; } } From 28f7d429fc5cc6a8e52766d06d6a261825d792c2 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sat, 19 Nov 2016 02:27:31 +0000 Subject: [PATCH 067/305] REST console v2. This is an incompatible protocol change. It degrades gracefully. --- OpenSim/Framework/Console/RemoteConsole.cs | 317 +++++++++++++++++---- 1 file changed, 263 insertions(+), 54 deletions(-) diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs index 8ad7b0daa9..9049b4b801 100644 --- a/OpenSim/Framework/Console/RemoteConsole.cs +++ b/OpenSim/Framework/Console/RemoteConsole.cs @@ -34,6 +34,7 @@ using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading; +using System.Timers; using OpenMetaverse; using Nini.Config; using OpenSim.Framework.Servers.HttpServer; @@ -41,90 +42,232 @@ using log4net; namespace OpenSim.Framework.Console { - public class ConsoleConnection - { - public int last; - public long lastLineSeen; - public bool newConnection = true; - } - // A console that uses REST interfaces // public class RemoteConsole : CommandConsole { - private IHttpServer m_Server = null; - private IConfigSource m_Config = null; + // Connection specific data, indexed by a session ID + // we create when a client connects. + protected class ConsoleConnection + { + // Last activity from the client + public int last; - private List m_Scrollback = new List(); - private ManualResetEvent m_DataEvent = new ManualResetEvent(false); - private List m_InputData = new List(); - private long m_LineNumber = 0; - private Dictionary m_Connections = + // Last line of scrollback posted to this client + public long lastLineSeen; + + // True if this is a new connection, e.g. has never + // displayed a prompt to the user. + public bool newConnection = true; + } + + // A line in the scrollback buffer. + protected class ScrollbackEntry + { + // The line number of this entry + public long lineNumber; + + // The text to send to the client + public string text; + + // The level this should be logged as. Omitted for + // prompts and input echo. + public string level; + + // True if the text above is a prompt, e.g. the + // client should turn on the cursor / accept input + public bool isPrompt; + + // True if the requested input is a command. A + // client may offer help or validate input if + // this is set. If false, input should be sent + // as typed. + public bool isCommand; + + // True if this text represents a line of text that + // was input in response to a prompt. A client should + // turn off the cursor and refrain from sending commands + // until a new prompt is received. + public bool isInput; + } + + // Data that is relevant to all connections + + // The scrollback buffer + protected List m_Scrollback = new List(); + + // Monotonously incrementing line number. This may eventually + // wrap. No provision is made for that case because 64 bits + // is a long, long time. + protected long m_lineNumber = 0; + + // These two variables allow us to send the correct + // information about the prompt status to the client, + // irrespective of what may have run off the top of the + // scrollback buffer; + protected bool m_expectingInput = false; + protected bool m_expectingCommand = true; + protected string m_lastPromptUsed; + + // This is the list of things received from clients. + // Note: Race conditions can happen. If a client sends + // something while nothing is expected, it will be + // intepreted as input to the next prompt. For + // commands this is largely correct. For other prompts, + // YMMV. + // TODO: Find a better way to fix this + protected List m_InputData = new List(); + + // Event to allow ReadLine to wait synchronously even though + // everthing else is asynchronous here. + protected ManualResetEvent m_DataEvent = new ManualResetEvent(false); + + // The list of sessions we maintain. Unlike other console types, + // multiple users on the same console are explicitly allowed. + protected Dictionary m_Connections = new Dictionary(); - private string m_UserName = String.Empty; - private string m_Password = String.Empty; - private string m_AllowedOrigin = String.Empty; + + // Timer to control expiration of sessions that have been + // disconnected. + protected System.Timers.Timer m_expireTimer = new System.Timers.Timer(5000); + + // The less interesting stuff that makes the actual server + // work. + protected IHttpServer m_Server = null; + protected IConfigSource m_Config = null; + + protected string m_UserName = String.Empty; + protected string m_Password = String.Empty; + protected string m_AllowedOrigin = String.Empty; + public RemoteConsole(string defaultPrompt) : base(defaultPrompt) { + // There is something wrong with this architecture. + // A prompt is sent on every single input, so why have this? + // TODO: Investigate and fix. + m_lastPromptUsed = defaultPrompt; + + // Start expiration of sesssions. + m_expireTimer.Elapsed += DoExpire; + m_expireTimer.Start(); } public void ReadConfig(IConfigSource config) { m_Config = config; + // We're pulling this from the 'Network' section for legacy + // compatibility. However, this is so essentially insecure + // that TLS and client certs should be used instead of + // a username / password. IConfig netConfig = m_Config.Configs["Network"]; + if (netConfig == null) return; + // Get the username and password. m_UserName = netConfig.GetString("ConsoleUser", String.Empty); m_Password = netConfig.GetString("ConsolePass", String.Empty); + + // Woefully underdocumented, this is what makes javascript + // console clients work. Set to "*" for anywhere or (better) + // to specific addresses. m_AllowedOrigin = netConfig.GetString("ConsoleAllowedOrigin", String.Empty); } public void SetServer(IHttpServer server) { + // This is called by the framework to give us the server + // instance (means: port) to work with. m_Server = server; + // Add our handlers m_Server.AddHTTPHandler("/StartSession/", HandleHttpStartSession); m_Server.AddHTTPHandler("/CloseSession/", HandleHttpCloseSession); m_Server.AddHTTPHandler("/SessionCommand/", HandleHttpSessionCommand); } public override void Output(string text, string level) + { + Output(text, level, false, false, false); + } + + protected void Output(string text, string level, bool isPrompt, bool isCommand, bool isInput) { + // Increment the line number. It was 0 and they start at 1 + // so we need to pre-increment. + m_lineNumber++; + + // Create and populate the new entry. + ScrollbackEntry newEntry = new ScrollbackEntry(); + + newEntry.lineNumber = m_lineNumber; + newEntry.text = text; + newEntry.level = level; + newEntry.isPrompt = isPrompt; + newEntry.isCommand = isCommand; + newEntry.isInput = isInput; + + // Add a line to the scrollback. In some cases, that may not + // actually be a line of text. lock (m_Scrollback) { + // Prune the scrollback to the length se send as connect + // burst to give the user some context. while (m_Scrollback.Count >= 1000) m_Scrollback.RemoveAt(0); - m_LineNumber++; - m_Scrollback.Add(String.Format("{0}", m_LineNumber)+":"+level+":"+text); + + m_Scrollback.Add(newEntry); } + + // Let the rest of the system know we have output something. FireOnOutput(text.Trim()); + + // Also display it for debugging. System.Console.WriteLine(text.Trim()); } public override void Output(string text) { - Output(text, "normal"); + // Output plain (non-logging style) text. + Output(text, String.Empty, false, false, false); } public override string ReadLine(string p, bool isCommand, bool e) { - if (isCommand) - Output("+++"+p); - else - Output("-++"+p); + // Output the prompt an prepare to wait. This + // is called on a dedicated console thread and + // needs to be synchronous. Old architecture but + // not worth upgrading. + if (isCommand) + { + m_expectingInput = true; + m_expectingCommand = true; + Output(p, String.Empty, true, true, false); + m_lastPromptUsed = p; + } + else + { + m_expectingInput = true; + Output(p, String.Empty, true, false, false); + } + + // Here is where we wait for the user to input something. m_DataEvent.WaitOne(); string cmdinput; + // Check for empty input. Read input if not empty. lock (m_InputData) { if (m_InputData.Count == 0) { m_DataEvent.Reset(); + m_expectingInput = false; + m_expectingCommand = false; + return ""; } @@ -135,8 +278,19 @@ namespace OpenSim.Framework.Console } + m_expectingInput = false; + m_expectingCommand = false; + + // Echo to all the other users what we have done. This + // will also go to ourselves. + Output (cmdinput, String.Empty, false, false, true); + + // If this is a command, we need to resolve and execute it. if (isCommand) { + // This call will actually execute the command and create + // any output associated with it. The core just gets an + // empty string so it will call again immediately. string[] cmd = Commands.Resolve(Parser.Parse(cmdinput)); if (cmd.Length != 0) @@ -151,18 +305,23 @@ namespace OpenSim.Framework.Console return String.Empty; } } + + // Return the raw input string if not a command. return cmdinput; } - private Hashtable CheckOrigin(Hashtable result) + // Very simplistic static access control header. + protected Hashtable CheckOrigin(Hashtable result) { if (!string.IsNullOrEmpty(m_AllowedOrigin)) result["access_control_allow_origin"] = m_AllowedOrigin; + return result; } + /* TODO: Figure out how PollServiceHTTPHandler can access the request headers * in order to use m_AllowedOrigin as a regular expression - private Hashtable CheckOrigin(Hashtable headers, Hashtable result) + protected Hashtable CheckOrigin(Hashtable headers, Hashtable result) { if (!string.IsNullOrEmpty(m_AllowedOrigin)) { @@ -177,18 +336,23 @@ namespace OpenSim.Framework.Console } */ - private void DoExpire() + protected void DoExpire(Object sender, ElapsedEventArgs e) { + // Iterate the list of console connections and find those we + // haven't heard from for longer then the longpoll interval. + // Remove them. List expired = new List(); lock (m_Connections) { + // Mark the expired ones foreach (KeyValuePair kvp in m_Connections) { if (System.Environment.TickCount - kvp.Value.last > 500000) expired.Add(kvp.Key); } + // Delete them foreach (UUID id in expired) { m_Connections.Remove(id); @@ -197,10 +361,10 @@ namespace OpenSim.Framework.Console } } - private Hashtable HandleHttpStartSession(Hashtable request) + // Start a new session. + protected Hashtable HandleHttpStartSession(Hashtable request) { - DoExpire(); - + // The login is in the form of a http form post Hashtable post = DecodePostString(request["body"].ToString()); Hashtable reply = new Hashtable(); @@ -208,6 +372,7 @@ namespace OpenSim.Framework.Console reply["int_response_code"] = 401; reply["content_type"] = "text/plain"; + // Check user name and password if (m_UserName == String.Empty) return reply; @@ -220,22 +385,28 @@ namespace OpenSim.Framework.Console return reply; } + // Set up the new console connection record ConsoleConnection c = new ConsoleConnection(); c.last = System.Environment.TickCount; c.lastLineSeen = 0; + // Assign session ID UUID sessionID = UUID.Random(); + // Add connection to list. lock (m_Connections) { m_Connections[sessionID] = c; } + // This call is a CAP. The URL is the authentication. string uri = "/ReadResponses/" + sessionID.ToString() + "/"; m_Server.AddPollServiceHTTPHandler( uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout + // Our reply is an XML document. + // TODO: Change this to Linq.Xml XmlDocument xmldoc = new XmlDocument(); XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, "", ""); @@ -252,12 +423,13 @@ namespace OpenSim.Framework.Console rootElement.AppendChild(id); XmlElement prompt = xmldoc.CreateElement("", "Prompt", ""); - prompt.AppendChild(xmldoc.CreateTextNode(DefaultPrompt)); + prompt.AppendChild(xmldoc.CreateTextNode(m_lastPromptUsed)); rootElement.AppendChild(prompt); rootElement.AppendChild(MainConsole.Instance.Commands.GetXml(xmldoc)); + // Set up the response and check origin reply["str_response_string"] = xmldoc.InnerXml; reply["int_response_code"] = 200; reply["content_type"] = "text/xml"; @@ -266,10 +438,9 @@ namespace OpenSim.Framework.Console return reply; } - private Hashtable HandleHttpCloseSession(Hashtable request) + // Client closes session. Clean up. + protected Hashtable HandleHttpCloseSession(Hashtable request) { - DoExpire(); - Hashtable post = DecodePostString(request["body"].ToString()); Hashtable reply = new Hashtable(); @@ -316,10 +487,9 @@ namespace OpenSim.Framework.Console return reply; } - private Hashtable HandleHttpSessionCommand(Hashtable request) + // Command received from the client. + protected Hashtable HandleHttpSessionCommand(Hashtable request) { - DoExpire(); - Hashtable post = DecodePostString(request["body"].ToString()); Hashtable reply = new Hashtable(); @@ -327,6 +497,7 @@ namespace OpenSim.Framework.Console reply["int_response_code"] = 404; reply["content_type"] = "text/plain"; + // Check the ID if (post["ID"] == null) return reply; @@ -334,21 +505,25 @@ namespace OpenSim.Framework.Console if (!UUID.TryParse(post["ID"].ToString(), out id)) return reply; + // Find the connection for that ID. lock (m_Connections) { if (!m_Connections.ContainsKey(id)) return reply; } + // Empty post. Just error out. if (post["COMMAND"] == null) return reply; + // Place the input data in the buffer. lock (m_InputData) { m_DataEvent.Set(); m_InputData.Add(post["COMMAND"].ToString()); } + // Create the XML reply document. XmlDocument xmldoc = new XmlDocument(); XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, "", ""); @@ -372,7 +547,8 @@ namespace OpenSim.Framework.Console return reply; } - private Hashtable DecodePostString(string data) + // Decode a HTTP form post to a Hashtable + protected Hashtable DecodePostString(string data) { Hashtable result = new Hashtable(); @@ -396,6 +572,7 @@ namespace OpenSim.Framework.Console return result; } + // Close the CAP receiver for the responses for a given client. public void CloseConnection(UUID id) { try @@ -409,7 +586,9 @@ namespace OpenSim.Framework.Console } } - private bool HasEvents(UUID RequestID, UUID sessionID) + // Check if there is anything to send. Return true if this client has + // lines pending. + protected bool HasEvents(UUID RequestID, UUID sessionID) { ConsoleConnection c = null; @@ -420,13 +599,15 @@ namespace OpenSim.Framework.Console c = m_Connections[sessionID]; } c.last = System.Environment.TickCount; - if (c.lastLineSeen < m_LineNumber) + if (c.lastLineSeen < m_lineNumber) return true; return false; } - private Hashtable GetEvents(UUID RequestID, UUID sessionID) + // Send all pending output to the client. + protected Hashtable GetEvents(UUID RequestID, UUID sessionID) { + // Find the connection that goes with this client. ConsoleConnection c = null; lock (m_Connections) @@ -435,12 +616,15 @@ namespace OpenSim.Framework.Console return NoEvents(RequestID, UUID.Zero); c = m_Connections[sessionID]; } + + // If we have nothing to send, send the no events response. c.last = System.Environment.TickCount; - if (c.lastLineSeen >= m_LineNumber) + if (c.lastLineSeen >= m_lineNumber) return NoEvents(RequestID, UUID.Zero); Hashtable result = new Hashtable(); + // Create the response document. XmlDocument xmldoc = new XmlDocument(); XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, "", ""); @@ -449,30 +633,53 @@ namespace OpenSim.Framework.Console XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", ""); - if (c.newConnection) - { - c.newConnection = false; - Output("+++" + DefaultPrompt); - } + //if (c.newConnection) + //{ + // c.newConnection = false; + // Output("+++" + DefaultPrompt); + //} lock (m_Scrollback) { - long startLine = m_LineNumber - m_Scrollback.Count; + long startLine = m_lineNumber - m_Scrollback.Count; long sendStart = startLine; if (sendStart < c.lastLineSeen) sendStart = c.lastLineSeen; - for (long i = sendStart ; i < m_LineNumber ; i++) + for (long i = sendStart ; i < m_lineNumber ; i++) { + ScrollbackEntry e = m_Scrollback[(int)(i - startLine)]; + XmlElement res = xmldoc.CreateElement("", "Line", ""); - long line = i + 1; - res.SetAttribute("Number", line.ToString()); - res.AppendChild(xmldoc.CreateTextNode(m_Scrollback[(int)(i - startLine)])); + res.SetAttribute("Number", e.lineNumber.ToString()); + res.SetAttribute("Level", e.level); + // Don't include these for the scrollback, we'll send the + // real state later. + if (!c.newConnection) + { + res.SetAttribute("Prompt", e.isPrompt ? "true" : "false"); + res.SetAttribute("Command", e.isCommand ? "true" : "false"); + res.SetAttribute("Input", e.isInput ? "true" : "false"); + } + else if (i == m_lineNumber - 1) // Last line for a new connection + { + res.SetAttribute("Prompt", m_expectingInput ? "true" : "false"); + res.SetAttribute("Command", m_expectingCommand ? "true" : "false"); + res.SetAttribute("Input", (!m_expectingInput) ? "true" : "false"); + } + else + { + res.SetAttribute("Input", e.isInput ? "true" : "false"); + } + + res.AppendChild(xmldoc.CreateTextNode(e.text)); rootElement.AppendChild(res); } } - c.lastLineSeen = m_LineNumber; + + c.lastLineSeen = m_lineNumber; + c.newConnection = false; xmldoc.AppendChild(rootElement); @@ -486,7 +693,9 @@ namespace OpenSim.Framework.Console return result; } - private Hashtable NoEvents(UUID RequestID, UUID id) + // This is really just a no-op. It generates what is sent + // to the client if the poll times out without any events. + protected Hashtable NoEvents(UUID RequestID, UUID id) { Hashtable result = new Hashtable(); From 8010413e645e1aaf655008e216c017943a5d8c76 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 19 Nov 2016 21:06:42 +0000 Subject: [PATCH 068/305] remove some potencial null refs i did add in last days :( --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 8 ++++++-- OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | 3 --- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 8ba26e83f9..55d4e39818 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -620,7 +620,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityProps = null; m_killRecord.Clear(); GroupsInView.Clear(); - m_scene = null; +// m_scene = null; can't do this unless checks are added everywhere due to workitems already in pools + //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); //GC.Collect(); //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); @@ -4371,7 +4372,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP ushort timeDilation; - if(m_scene == null) + if(!IsActive) return; timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); @@ -12945,6 +12946,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// provide your own method. protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method) { + if(!IsActive) + return; + if (m_outPacketsToDrop != null) if (m_outPacketsToDrop.Contains(packet.Type.ToString())) return; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index e85cee2524..0efa7c55cd 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -299,10 +299,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP OnQueueEmpty = null; PendingAcks.Clear(); NeedAcks.Clear(); - NeedAcks = null; - PendingAcks = null; m_nextPackets = null; - m_packetOutboxes = null; } /// From b887b7625e03a3923e8eea72353c878bc1d4b3a9 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 19 Nov 2016 21:53:09 +0000 Subject: [PATCH 069/305] change OutPacket drop condition --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 55d4e39818..05a3191047 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -12946,12 +12946,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// provide your own method. protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method) { - if(!IsActive) + if(!m_udpClient.IsConnected) + { + PacketPool.Instance.ReturnPacket(packet); return; + } if (m_outPacketsToDrop != null) + { if (m_outPacketsToDrop.Contains(packet.Type.ToString())) + { + PacketPool.Instance.ReturnPacket(packet); return; + } + } if (DebugPacketLevel > 0) { From 586c81eecda0193e3403135ad308f8e9887f1456 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 20 Nov 2016 01:49:53 +0000 Subject: [PATCH 070/305] give up on OutPacket drop condition on closing --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 05a3191047..5879e56668 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -12946,12 +12946,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// provide your own method. protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method) { + +/* this is causing packet loss for some reason if(!m_udpClient.IsConnected) { PacketPool.Instance.ReturnPacket(packet); return; } - +*/ if (m_outPacketsToDrop != null) { if (m_outPacketsToDrop.Contains(packet.Type.ToString())) From 200183caf7c3673e914a7b7f30fbb47bc7e92c44 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 20 Nov 2016 02:49:40 +0000 Subject: [PATCH 071/305] HG protocol is still broken for large regions. work around it on teleport via lm --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | 1 - .../Framework/EntityTransfer/HGEntityTransferModule.cs | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 0efa7c55cd..c804e3305e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -299,7 +299,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OnQueueEmpty = null; PendingAcks.Clear(); NeedAcks.Clear(); - m_nextPackets = null; } /// diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index a9aaf124b9..49307f6ce9 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -515,7 +515,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer GridRegion info = Scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); // Local region? - if (info != null) + // HG link is broken for large regions + // so ignore its information so lms to large regions can work + if (info != null && info.RegionLocY != 0) { Scene.RequestTeleportLocation( remoteClient, info.RegionHandle, lm.Position, From 93d502e0cf5d6822d950a4e29c5d5fea9513f9ce Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 20 Nov 2016 03:19:19 +0000 Subject: [PATCH 072/305] HG UserAgent, return serverURI --- OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs index e112e0e1ff..37feabe8b9 100644 --- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs @@ -139,6 +139,7 @@ namespace OpenSim.Server.Handlers.Hypergrid hash["region_name"] = regInfo.RegionName; hash["hostname"] = regInfo.ExternalHostName; hash["http_port"] = regInfo.HttpPort.ToString(); + hash["server_uri"] = regInfo.ServerURI; hash["internal_port"] = regInfo.InternalEndPoint.Port.ToString(); hash["position"] = position.ToString(); hash["lookAt"] = lookAt.ToString(); From e2b580e56906f76e74abfdac5a11a1c1bbc31252 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 20 Nov 2016 03:51:38 +0000 Subject: [PATCH 073/305] HG LinkRegion sends region size also --- OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs | 6 +++++- OpenSim/Services/HypergridService/GatekeeperService.cs | 8 +++++++- OpenSim/Services/Interfaces/IHypergridServices.cs | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs index c7ac9be132..cb15138465 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs @@ -70,13 +70,17 @@ namespace OpenSim.Server.Handlers.Hypergrid string imageURL = string.Empty; ulong regionHandle = 0; string reason = string.Empty; + int sizeX = 256; + int sizeY = 256; - bool success = m_GatekeeperService.LinkRegion(name, out regionID, out regionHandle, out externalName, out imageURL, out reason); + bool success = m_GatekeeperService.LinkRegion(name, out regionID, out regionHandle, out externalName, out imageURL, out reason, out sizeX, out sizeY); Hashtable hash = new Hashtable(); hash["result"] = success.ToString(); hash["uuid"] = regionID.ToString(); hash["handle"] = regionHandle.ToString(); + hash["size_x"] = sizeX; + hash["size_y"] = sizeY; hash["region_image"] = imageURL; hash["external_name"] = externalName; diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index 9643a8bd72..41e2b4057f 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -162,10 +162,12 @@ namespace OpenSim.Services.HypergridService exceptions.Add(s.Trim()); } - public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason) + public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason, out int sizeX, out int sizeY) { regionID = UUID.Zero; regionHandle = 0; + sizeX = (int)Constants.RegionSize; + sizeY = (int)Constants.RegionSize; externalName = m_ExternalName + ((regionName != string.Empty) ? " " + regionName : ""); imageURL = string.Empty; reason = string.Empty; @@ -199,6 +201,8 @@ namespace OpenSim.Services.HypergridService regionID = region.RegionID; regionHandle = region.RegionHandle; + sizeX = region.RegionSizeX; + sizeY = region.RegionSizeY; string regionimage = "regionImage" + regionID.ToString(); regionimage = regionimage.Replace("-", ""); @@ -275,6 +279,7 @@ namespace OpenSim.Services.HypergridService if (!am.Success) { + reason = "Login failed: client " + curViewer + " is not allowed"; m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is not allowed", curViewer); return false; } @@ -287,6 +292,7 @@ namespace OpenSim.Services.HypergridService if (dm.Success) { + reason = "Login failed: client " + curViewer + " is denied"; m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is denied", curViewer); return false; } diff --git a/OpenSim/Services/Interfaces/IHypergridServices.cs b/OpenSim/Services/Interfaces/IHypergridServices.cs index 5e012fb173..1815e6cee8 100644 --- a/OpenSim/Services/Interfaces/IHypergridServices.cs +++ b/OpenSim/Services/Interfaces/IHypergridServices.cs @@ -36,7 +36,7 @@ namespace OpenSim.Services.Interfaces { public interface IGatekeeperService { - bool LinkRegion(string regionDescriptor, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason); + bool LinkRegion(string regionDescriptor, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason, out int sizeX, out int sizeY); /// /// Returns the region a Hypergrid visitor should enter. From 4c2ece3bcb7a28c746ef42b7cc6939571e0ede3b Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 20 Nov 2016 04:22:00 +0000 Subject: [PATCH 074/305] HG LinkRegion receive region size also. Useless since olde r gatekeepers dont send it --- .../Hypergrid/GatekeeperServiceConnector.cs | 13 +++++++++++-- OpenSim/Services/GridService/HypergridLinker.cs | 8 ++++++-- OpenSim/Services/LLLoginService/LLLoginService.cs | 5 ++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs index aad3bd220a..eef492d4b4 100644 --- a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs @@ -73,13 +73,15 @@ namespace OpenSim.Services.Connectors.Hypergrid return "foreignobject/"; } - public bool LinkRegion(GridRegion info, out UUID regionID, out ulong realHandle, out string externalName, out string imageURL, out string reason) + public bool LinkRegion(GridRegion info, out UUID regionID, out ulong realHandle, out string externalName, out string imageURL, out string reason, out int sizeX, out int sizeY) { regionID = UUID.Zero; imageURL = string.Empty; realHandle = 0; externalName = string.Empty; reason = string.Empty; + sizeX = (int)Constants.RegionSize; + sizeY = (int)Constants.RegionSize; Hashtable hash = new Hashtable(); hash["region_name"] = info.RegionName; @@ -134,8 +136,15 @@ namespace OpenSim.Services.Connectors.Hypergrid externalName = (string)hash["external_name"]; //m_log.Debug(">> HERE, externalName: " + externalName); } + if (hash["size_x"] != null) + { + Int32.TryParse((string)hash["size_x"], out sizeX); + } + if (hash["size_y"] != null) + { + Int32.TryParse((string)hash["size_y"], out sizeY); + } } - } catch (Exception e) { diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs index 2af617a4f4..db33b1a486 100644 --- a/OpenSim/Services/GridService/HypergridLinker.cs +++ b/OpenSim/Services/GridService/HypergridLinker.cs @@ -198,7 +198,7 @@ namespace OpenSim.Services.GridService mapName = mapName.Trim(); - if (!mapName.StartsWith("http")) + if (!mapName.StartsWith("http") && !!mapName.StartsWith("https")) { // Formats: grid.example.com:8002:region name // grid.example.com:region name @@ -365,7 +365,9 @@ namespace OpenSim.Services.GridService UUID regionID = UUID.Zero; string externalName = string.Empty; string imageURL = string.Empty; - if (!m_GatekeeperConnector.LinkRegion(regInfo, out regionID, out handle, out externalName, out imageURL, out reason)) + int sizeX = (int)Constants.RegionSize; + int sizeY = (int)Constants.RegionSize; + if (!m_GatekeeperConnector.LinkRegion(regInfo, out regionID, out handle, out externalName, out imageURL, out reason, out sizeX, out sizeY)) return false; if (regionID == UUID.Zero) @@ -397,6 +399,8 @@ namespace OpenSim.Services.GridService // } regInfo.RegionID = regionID; + regInfo.RegionSizeX = sizeX; + regInfo.RegionSizeY = sizeY; if (externalName == string.Empty) regInfo.RegionName = regInfo.ServerURI; diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 1ea17b502c..6d63959a2a 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -785,7 +785,10 @@ namespace OpenSim.Services.LLLoginService ulong handle; string imageURL = string.Empty, reason = string.Empty; string message; - if (m_GatekeeperConnector.LinkRegion(gatekeeper, out regionID, out handle, out domainName, out imageURL, out reason)) + int sizeX = (int)Constants.RegionSize; + int sizeY = (int)Constants.RegionSize; + + if (m_GatekeeperConnector.LinkRegion(gatekeeper, out regionID, out handle, out domainName, out imageURL, out reason, out sizeX, out sizeY)) { string homeURI = null; if (account.ServiceURLs != null && account.ServiceURLs.ContainsKey("HomeURI")) From 902e8019de4c61379e3dc51f506bd4a1af0a9df3 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 20 Nov 2016 05:06:50 +0000 Subject: [PATCH 075/305] HG add a small delay before start sending region data --- .../Region/Framework/Scenes/ScenePresence.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 2cfdd946f9..7efd9200ed 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2071,14 +2071,13 @@ namespace OpenSim.Region.Framework.Scenes m_log.DebugFormat("[CompleteMovement]: Missing COF for {0} is {1}", client.AgentId, COF); } - if(!gotCrossUpdate) - RotateToLookAt(look); // Tell the client that we're totally ready ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); m_log.DebugFormat("[CompleteMovement] MoveAgentIntoRegion: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + if (!string.IsNullOrEmpty(m_callbackURI)) { // We cannot sleep here since this would hold up the inbound packet processing thread, as @@ -2107,12 +2106,28 @@ namespace OpenSim.Region.Framework.Scenes // client.Name, client.AgentId, m_scene.RegionInfo.RegionName); // } + m_log.DebugFormat("[CompleteMovement] ReleaseAgent: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + if(m_teleportFlags > 0) //sanity check + gotCrossUpdate = false; + + if(!gotCrossUpdate) + RotateToLookAt(look); + + // start sending terrain patchs if (!gotCrossUpdate && !isNPC) Scene.SendLayerData(ControllingClient); + // HG delay + if((m_teleportFlags & TeleportFlags.ViaHGLogin) != 0) + { + Thread.Sleep(500); + m_log.DebugFormat("[CompleteMovement] HG delay: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + } + m_previusParcelHide = false; m_previusParcelUUID = UUID.Zero; m_currentParcelHide = false; From f1958e9f71f5ba9b8ca088f23df68336a3c7b43c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 20 Nov 2016 13:36:34 +0000 Subject: [PATCH 076/305] revert more object references removal on clients close because 2 many code paths don't have proper abort --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 3 +-- OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 5879e56668..65a341e274 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -606,11 +606,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP //m_scene.CloseAllAgents(CircuitCode); // Disable UDP handling for this client - m_udpClient.Shutdown(); - m_udpClient.OnQueueEmpty -= HandleQueueEmpty; m_udpClient.HasUpdates -= HandleHasUpdates; m_udpClient.OnPacketStats -= PopulateStats; + m_udpClient.Shutdown(); // Shutdown the image manager ImageManager.Close(); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index c804e3305e..dc8ac3c41c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -288,15 +288,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) { m_packetOutboxes[i].Clear(); - m_throttleCategories[i] = null; m_nextPackets[i] = null; } // pull the throttle out of the scene throttle m_throttleClient.Parent.UnregisterRequest(m_throttleClient); - m_throttleClient = null; - OnPacketStats = null; - OnQueueEmpty = null; PendingAcks.Clear(); NeedAcks.Clear(); } From 1d998a770b2c4ce53b0482d1360668ea4142ebe0 Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Sun, 20 Nov 2016 13:52:06 +0000 Subject: [PATCH 077/305] Change some minor log messages to debug level in Rest client code. --- OpenSim/Framework/RestClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/RestClient.cs b/OpenSim/Framework/RestClient.cs index ca1939218b..26237deae4 100644 --- a/OpenSim/Framework/RestClient.cs +++ b/OpenSim/Framework/RestClient.cs @@ -430,11 +430,11 @@ namespace OpenSim.Framework using (Stream dst = _request.GetRequestStream()) { - m_log.Info("[REST]: GetRequestStream is ok"); + m_log.Debug("[REST]: GetRequestStream is ok"); byte[] buf = new byte[1024]; int length = src.Read(buf, 0, 1024); - m_log.Info("[REST]: First Read is ok"); + m_log.Debug("[REST]: First Read is ok"); while (length > 0) { dst.Write(buf, 0, length); From 05f70024451e99f8e136499c04d645960a6b5f3a Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Sun, 20 Nov 2016 14:20:54 +0000 Subject: [PATCH 078/305] Include config option to disable stats thread showing read/write stats in console. Keeping default as true to retain current behaviour. Also checked to prevent counters being added to so there wont be any integer overflows over time --- .../Services/FSAssetService/FSAssetService.cs | 30 ++++++++++++++----- bin/Robust.HG.ini.example | 3 ++ bin/Robust.ini.example | 3 ++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/OpenSim/Services/FSAssetService/FSAssetService.cs b/OpenSim/Services/FSAssetService/FSAssetService.cs index 9ec2d00a57..7f1446272e 100644 --- a/OpenSim/Services/FSAssetService/FSAssetService.cs +++ b/OpenSim/Services/FSAssetService/FSAssetService.cs @@ -77,6 +77,7 @@ namespace OpenSim.Services.FSAssetService protected int m_missingAssetsFS = 0; protected string m_FSBase; protected bool m_useOsgridFormat = false; + protected bool m_showStats = true; private static bool m_Initialized; private bool m_MainInstance; @@ -186,6 +187,9 @@ namespace OpenSim.Services.FSAssetService m_useOsgridFormat = assetConfig.GetBoolean("UseOsgridFormat", m_useOsgridFormat); + // Default is to show stats to retain original behaviour + m_showStats = assetConfig.GetBoolean("ShowConsoleStats", m_showStats); + if (m_MainInstance) { string loader = assetConfig.GetString("DefaultAssetLoader", string.Empty); @@ -203,8 +207,12 @@ namespace OpenSim.Services.FSAssetService m_WriterThread = new Thread(Writer); m_WriterThread.Start(); - m_StatsThread = new Thread(Stats); - m_StatsThread.Start(); + + if (m_showStats) + { + m_StatsThread = new Thread(Stats); + m_StatsThread.Start(); + } } m_log.Info("[FSASSETS]: FS asset service enabled"); @@ -441,7 +449,7 @@ namespace OpenSim.Services.FSAssetService Store(asset); } } - if (asset == null) + if (asset == null && m_showStats) { // m_log.InfoFormat("[FSASSETS]: Asset {0} not found", id); m_missingAssets++; @@ -469,8 +477,11 @@ namespace OpenSim.Services.FSAssetService } } if (asset == null) - m_missingAssetsFS++; - // m_log.InfoFormat("[FSASSETS]: Asset {0}, hash {1} not found in FS", id, hash); + { + if (m_showStats) + m_missingAssetsFS++; + // m_log.InfoFormat("[FSASSETS]: Asset {0}, hash {1} not found in FS", id, hash); + } else { // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) @@ -484,10 +495,13 @@ namespace OpenSim.Services.FSAssetService } } - lock (m_statsLock) + if (m_showStats) { - m_readTicks += Environment.TickCount - startTime; - m_readCount++; + lock (m_statsLock) + { + m_readTicks += Environment.TickCount - startTime; + m_readCount++; + } } // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index ad076743d3..c231a8a5ca 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -242,6 +242,9 @@ ;; Reduces DB calls if asset is requested often. Default value 0 will always update access time ;DaysBetweenAccessTimeUpdates = 30 + ;; Should FSAssets print read/write stats to the robust console, default is true + ;ShowConsoleStats = true + ;; FSAssets Custom Database Config (Leave blank to use grids default database configuration) ;StorageProvider = "" ;ConnectionString = "" diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 099d4da247..743b23dbc5 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -204,6 +204,9 @@ ;; Reduces DB calls if asset is requested often. Default value 0 will always update access time ;DaysBetweenAccessTimeUpdates = 30 + ;; Should FSAssets print read/write stats to the robust console, default is true + ;ShowConsoleStats = true + ;; FSAssets Custom Database Config (Leave blank to use grids default database configuration) ;StorageProvider = "" ;ConnectionString = "" From b70e48c8a5e13074480bdd89a810ff8c73dc8afb Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 20 Nov 2016 22:09:33 +0000 Subject: [PATCH 079/305] handle HG lm tp to large regions in another way --- .../EntityTransfer/EntityTransferModule.cs | 21 ++++++++++++++----- .../EntityTransfer/HGEntityTransferModule.cs | 4 +--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 71a0e525d2..1161571016 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -594,12 +594,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer uint x = 0, y = 0; Util.RegionHandleToWorldLoc(regionHandle, out x, out y); + GridRegion reg; + + // handle legacy HG. liked regions are mapped into y = 0 and have no size information + // so we can only search by base handle + if( y == 0) + { + reg = gridService.GetRegionByPosition(scope, (int)x, (int)y); + return reg; + } + // Compute the world location we're teleporting to double worldX = (double)x + position.X; double worldY = (double)y + position.Y; // Find the region that contains the position - GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY); + reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY); if (reg != null) { @@ -813,8 +823,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (OutSideViewRange) { m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}", - finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); + "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} size {3},{4} needs new child agent for agent {5} from {6}", + finalDestination.RegionName, newRegionX, newRegionY,newSizeX, newSizeY, sp.Name, Scene.Name); //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); #region IP Translation for NAT @@ -2180,8 +2190,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #endregion // NotFoundLocationCache class private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache(); -// needed for old grid code - protected GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) { // Since we don't know how big the regions could be, we have to search a very large area @@ -2191,6 +2199,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Given a world position, get the GridRegion info for // the region containing that point. + // for compatibility with old grids it does a scan to find large regions + // 0.9 grids to that + protected GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py, uint pSizeHint) { diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 49307f6ce9..a9aaf124b9 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -515,9 +515,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer GridRegion info = Scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); // Local region? - // HG link is broken for large regions - // so ignore its information so lms to large regions can work - if (info != null && info.RegionLocY != 0) + if (info != null) { Scene.RequestTeleportLocation( remoteClient, info.RegionHandle, lm.Position, From b2c553b459a8390aaadd8f7c65567b1e557226c2 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 21 Nov 2016 01:16:35 +0000 Subject: [PATCH 080/305] work around some warnings --- .../ClientStack/Linden/UDP/LLUDPClient.cs | 1 + .../ClientStack/Linden/UDP/LLUDPServer.cs | 2 +- .../ClientStack/Linden/UDP/OpenSimUDPBase.cs | 5 +++++ .../ClientStack/Linden/UDP/TokenBucket.cs | 22 ++++++++++++------- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index dc8ac3c41c..9449ffb9dc 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -111,6 +111,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// hooked to put more data on the empty queue public event QueueEmpty OnQueueEmpty; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design","CA1009:DeclareEventHandlersCorrectly")] public event Func HasUpdates; /// AgentID for this client diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index af33d17b7e..a868e3aa44 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -521,7 +521,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // if (usePools) // EnablePools(); - DisablePools(); + base.DisablePools(); } public void Start() diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 7171974db3..4d726b43dd 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -179,6 +179,11 @@ namespace OpenMetaverse // m_dropRandomGenerator = new Random(); } + ~OpenSimUDPBase() + { + if(m_udpSocket !=null) + try { m_udpSocket.Close(); } catch { } + } /// /// Start inbound UDP packet handling. /// diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs index d4603f80a5..cac57b221e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs @@ -97,7 +97,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// protected float m_burst; - public virtual float MaxDripRate { get; set; } + protected float m_maxDripRate = 0; + public virtual float MaxDripRate + { + get { return m_maxDripRate; } + set { m_maxDripRate = value; } + } public float RequestedBurst { @@ -134,7 +139,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// the system tick interval (typically around 15-22ms) protected float m_dripRate; - public virtual float RequestedDripRate + public float RequestedDripRate { get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } set { @@ -146,7 +151,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - public virtual float DripRate + public float DripRate { get { float rate = Math.Min(RequestedDripRate,TotalDripRequest); @@ -344,7 +349,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // greater than this. // - protected float m_maxDripRate = 0; public override float MaxDripRate { get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); } @@ -359,7 +363,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // // Adjust drip rate in response to network conditions. // - public virtual float AdjustedDripRate + public float AdjustedDripRate { get { return m_dripRate; } set @@ -380,12 +384,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP { m_enabled = enabled; - MaxDripRate = maxDripRate; + m_maxDripRate = (maxDripRate == 0 ? m_totalDripRequest : Math.Max(maxDripRate, m_minimumFlow)); if (enabled) - AdjustedDripRate = m_maxDripRate * .5f; + m_dripRate = m_maxDripRate * .5f; else - AdjustedDripRate = m_maxDripRate; + m_dripRate = m_maxDripRate; + if (m_parent != null) + m_parent.RegisterRequest(this, m_dripRate); } /// From f794ab1a6702cdfc073eec17168c280891b941b4 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 21 Nov 2016 01:22:01 +0000 Subject: [PATCH 081/305] remove something VS decided to add --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 9449ffb9dc..dc8ac3c41c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -111,7 +111,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// hooked to put more data on the empty queue public event QueueEmpty OnQueueEmpty; - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design","CA1009:DeclareEventHandlersCorrectly")] public event Func HasUpdates; /// AgentID for this client From bced98d6e9b5fe08fd50a1be88c10a83063c309e Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 21 Nov 2016 01:47:09 +0000 Subject: [PATCH 082/305] work around some more warnings --- .../AgentPreferences/RemoteAgentPreferencesServiceConnector.cs | 2 +- .../Connectors/AgentPreferences/AgentPreferencesConnector.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs index ad9544ad30..a827c4c306 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs @@ -61,7 +61,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.AgentPreferences get { return "RemoteAgentPreferencesServicesConnector"; } } - public override void Initialise(IConfigSource source) + public new void Initialise(IConfigSource source) { IConfig moduleConfig = source.Configs["Modules"]; if (moduleConfig != null) diff --git a/OpenSim/Services/Connectors/AgentPreferences/AgentPreferencesConnector.cs b/OpenSim/Services/Connectors/AgentPreferences/AgentPreferencesConnector.cs index 1dbc0c8fe2..0e72c8bedd 100644 --- a/OpenSim/Services/Connectors/AgentPreferences/AgentPreferencesConnector.cs +++ b/OpenSim/Services/Connectors/AgentPreferences/AgentPreferencesConnector.cs @@ -62,7 +62,7 @@ namespace OpenSim.Services.Connectors Initialise(source); } - public virtual void Initialise(IConfigSource source) + public void Initialise(IConfigSource source) { IConfig gridConfig = source.Configs["AgentPreferencesService"]; if (gridConfig == null) From 81ef04c9fda6cadf0de3ca3e0f93db5670ea43c7 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 21 Nov 2016 16:55:51 +0000 Subject: [PATCH 083/305] fix type bug on hyperlinks --- OpenSim/Services/GridService/HypergridLinker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs index db33b1a486..3b85160df9 100644 --- a/OpenSim/Services/GridService/HypergridLinker.cs +++ b/OpenSim/Services/GridService/HypergridLinker.cs @@ -198,7 +198,7 @@ namespace OpenSim.Services.GridService mapName = mapName.Trim(); - if (!mapName.StartsWith("http") && !!mapName.StartsWith("https")) + if (!mapName.StartsWith("http") && !mapName.StartsWith("https")) { // Formats: grid.example.com:8002:region name // grid.example.com:region name From 8c19ea910a404295292a09762fc48dadd2fce2d4 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 21 Nov 2016 23:34:33 +0000 Subject: [PATCH 084/305] remove a wrong virtual dec ( no overides, and cant really have if used on a constructor like in assetlandmark) --- OpenSim/Framework/AssetBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/AssetBase.cs b/OpenSim/Framework/AssetBase.cs index 33be612402..87fd04affe 100644 --- a/OpenSim/Framework/AssetBase.cs +++ b/OpenSim/Framework/AssetBase.cs @@ -155,7 +155,7 @@ namespace OpenSim.Framework } } - public virtual byte[] Data + public byte[] Data { get { return m_data; } set { m_data = value; } From 7524c7729f820a510278a712e658b0865f83d079 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 22 Nov 2016 01:34:07 +0000 Subject: [PATCH 085/305] change asset description max size --- OpenSim/Data/MySQL/MySQLAssetData.cs | 8 ++++++++ OpenSim/Data/MySQL/MySQLXAssetData.cs | 10 +++++----- OpenSim/Data/PGSQL/PGSQLAssetData.cs | 10 +++++----- OpenSim/Data/SQLite/SQLiteAssetData.cs | 10 +++++----- OpenSim/Framework/AssetBase.cs | 16 ++++++++++++++-- 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLAssetData.cs b/OpenSim/Data/MySQL/MySQLAssetData.cs index 1488e1a5bb..83e7e4cf3e 100644 --- a/OpenSim/Data/MySQL/MySQLAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLAssetData.cs @@ -170,6 +170,14 @@ namespace OpenSim.Data.MySQL } string assetDescription = asset.Description; + if(assetDescription.Length > AssetBase.MAX_LMASSET_DESC) + { + if(asset.Type == (sbyte) AssetType.Landmark) + assetDescription = assetDescription.Substring(0, AssetBase.MAX_LMASSET_DESC); + else + assetDescription = assetDescription.Substring(0, AssetBase.MAX_ASSET_DESC); + } + if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) { assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); diff --git a/OpenSim/Data/MySQL/MySQLXAssetData.cs b/OpenSim/Data/MySQL/MySQLXAssetData.cs index ec2bcc69e9..6c6f560a4c 100644 --- a/OpenSim/Data/MySQL/MySQLXAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLXAssetData.cs @@ -214,12 +214,12 @@ namespace OpenSim.Data.MySQL } string assetDescription = asset.Description; - if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) + if(assetDescription.Length > AssetBase.MAX_LMASSET_DESC) { - assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); - m_log.WarnFormat( - "[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", - asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); + if(asset.Type == (sbyte) AssetType.Landmark) + assetDescription = assetDescription.Substring(0, AssetBase.MAX_LMASSET_DESC); + else + assetDescription = assetDescription.Substring(0, AssetBase.MAX_ASSET_DESC); } if (m_enableCompression) diff --git a/OpenSim/Data/PGSQL/PGSQLAssetData.cs b/OpenSim/Data/PGSQL/PGSQLAssetData.cs index 81adb034a9..97ea6a4ab5 100644 --- a/OpenSim/Data/PGSQL/PGSQLAssetData.cs +++ b/OpenSim/Data/PGSQL/PGSQLAssetData.cs @@ -175,12 +175,12 @@ namespace OpenSim.Data.PGSQL } string assetDescription = asset.Description; - if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) + if(assetDescription.Length > AssetBase.MAX_LMASSET_DESC) { - assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); - m_log.WarnFormat( - "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", - asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); + if(asset.Type == (sbyte) AssetType.Landmark) + assetDescription = assetDescription.Substring(0, AssetBase.MAX_LMASSET_DESC); + else + assetDescription = assetDescription.Substring(0, AssetBase.MAX_ASSET_DESC); } using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) diff --git a/OpenSim/Data/SQLite/SQLiteAssetData.cs b/OpenSim/Data/SQLite/SQLiteAssetData.cs index 9c2bd2e46e..9fbd9c7fab 100644 --- a/OpenSim/Data/SQLite/SQLiteAssetData.cs +++ b/OpenSim/Data/SQLite/SQLiteAssetData.cs @@ -143,12 +143,12 @@ namespace OpenSim.Data.SQLite } string assetDescription = asset.Description; - if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) + if(assetDescription.Length > AssetBase.MAX_LMASSET_DESC) { - assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); - m_log.WarnFormat( - "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", - asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); + if(asset.Type == (sbyte) AssetType.Landmark) + assetDescription = assetDescription.Substring(0, AssetBase.MAX_LMASSET_DESC); + else + assetDescription = assetDescription.Substring(0, AssetBase.MAX_ASSET_DESC); } //m_log.Info("[ASSET DB]: Creating Asset " + asset.FullID.ToString()); diff --git a/OpenSim/Framework/AssetBase.cs b/OpenSim/Framework/AssetBase.cs index 87fd04affe..67239ec105 100644 --- a/OpenSim/Framework/AssetBase.cs +++ b/OpenSim/Framework/AssetBase.cs @@ -51,7 +51,8 @@ namespace OpenSim.Framework private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public static readonly int MAX_ASSET_NAME = 64; - public static readonly int MAX_ASSET_DESC = 64; + public static readonly int MAX_ASSET_DESC = 127; + public static readonly int MAX_LMASSET_DESC = 255; /// /// Data of the Asset @@ -305,7 +306,18 @@ namespace OpenSim.Framework public string Description { get { return m_description; } - set { m_description = value; } + set + { + if(value.Length > AssetBase.MAX_LMASSET_DESC) + { + if(m_type == (sbyte) AssetType.Landmark) + m_description = value.Substring(0, AssetBase.MAX_LMASSET_DESC); + else + m_description = value.Substring(0, AssetBase.MAX_ASSET_DESC); + } + else + m_description = value; + } } public DateTime CreationDate From 4e64445c39c3de1941e071ff32d06702a3440d5d Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 22 Nov 2016 05:18:06 +0000 Subject: [PATCH 086/305] replace datetime.now on just timming by faster utcnow --- OpenSim/Region/Framework/Scenes/Scene.cs | 3 ++- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 6 +++--- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 5 ++--- .../Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index c349369604..09f0b19201 100755 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -5454,6 +5454,7 @@ Label_GroupsDone: public void CleanTempObjects() { + DateTime now = DateTime.UtcNow; EntityBase[] entities = GetEntities(); foreach (EntityBase obj in entities) { @@ -5465,7 +5466,7 @@ Label_GroupsDone: { if ((grp.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) { - if (grp.GetSittingAvatarsCount() == 0 && grp.RootPart.Expires <= DateTime.Now) + if (grp.GetSittingAvatarsCount() == 0 && grp.RootPart.Expires <= now) DeleteSceneObject(grp, false); } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index e643db7436..0cd738daa3 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -153,9 +153,9 @@ namespace OpenSim.Region.Framework.Scenes { m_scene.SceneGraph.FireChangeBackup(this); } - timeLastChanged = DateTime.Now.Ticks; + timeLastChanged = DateTime.UtcNow.Ticks; if (!m_hasGroupChanged) - timeFirstChanged = DateTime.Now.Ticks; + timeFirstChanged = DateTime.UtcNow.Ticks; if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null) { /* @@ -233,7 +233,7 @@ namespace OpenSim.Region.Framework.Scenes m_minPersistTime = m_scene.m_dontPersistBefore; } - long currentTime = DateTime.Now.Ticks; + long currentTime = DateTime.UtcNow.Ticks; if (timeLastChanged == 0) timeLastChanged = currentTime; if (timeFirstChanged == 0) timeFirstChanged = currentTime; diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 9d1dca2725..3a06e7df42 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -185,8 +185,7 @@ namespace OpenSim.Region.Framework.Scenes return !(SitTargetPosition == Vector3.Zero && (SitTargetOrientation == Quaternion.Identity // Valid Zero Rotation quaternion - || SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 1f && SitTargetOrientation.W == 0f // W-Z Mapping was invalid at one point - || SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 0f && SitTargetOrientation.W == 0f)); // Invalid Quaternion + || (SitTargetOrientation.W == 0f && SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 0f ))); // Invalid Quaternion } } @@ -1909,7 +1908,7 @@ namespace OpenSim.Region.Framework.Scenes public void ResetExpire() { - Expires = DateTime.Now + new TimeSpan(600000000); + Expires = DateTime.UtcNow + new TimeSpan(600000000); } public void AddFlag(PrimFlags flag) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index d72590792a..7129c8a241 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -880,7 +880,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance try { m_CurrentEvent = data.EventName; - m_EventStart = DateTime.Now; + m_EventStart = DateTime.UtcNow; m_InEvent = true; try @@ -1033,7 +1033,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance if (!m_InEvent) return 0; - return (DateTime.Now - m_EventStart).Seconds; + return (DateTime.UtcNow - m_EventStart).Seconds; } public void ResetScript(int timeout) From 385a265971372a556a94ef5f96ea61f9065c041d Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 22 Nov 2016 09:35:37 +0000 Subject: [PATCH 087/305] supress some warnings by explict(confirm) the hide of parent fields --- .../Region/CoreModules/Avatar/Chat/ChatModule.cs | 2 -- .../Avatar/Concierge/ConciergeModule.cs | 14 +++++--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs index fe0a243b9f..5164289970 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs @@ -55,9 +55,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat protected List FreezeCache = new List(); protected string m_adminPrefix = ""; protected object m_syncy = new object(); - protected IConfig m_config; - #region ISharedRegionModule Members public virtual void Initialise(IConfigSource config) { diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs index c48e58585e..c4a70c0d57 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs @@ -53,15 +53,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private const int DEBUG_CHANNEL = 2147483647; +// private const int DEBUG_CHANNEL = 2147483647; use base value - private List m_scenes = new List(); + private new List m_scenes = new List(); private List m_conciergedScenes = new List(); private bool m_replacingChatModule = false; - private IConfig m_config; - private string m_whoami = "conferencier"; private Regex m_regions = null; private string m_welcomes = null; @@ -72,14 +70,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge private string m_brokerURI = String.Empty; private int m_brokerUpdateTimeout = 300; - internal object m_syncy = new object(); + internal new object m_syncy = new object(); - internal bool m_enabled = false; + internal new bool m_enabled = false; #region ISharedRegionModule Members public override void Initialise(IConfigSource config) { - m_config = config.Configs["Concierge"]; + IConfig m_config = config.Configs["Concierge"]; if (null == m_config) return; @@ -89,7 +87,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge m_enabled = true; - // check whether ChatModule has been disabled: if yes, // then we'll "stand in" try @@ -136,7 +133,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge } } - public override void AddRegion(Scene scene) { if (!m_enabled) return; From b43717a39721adf14cb84d9d43055036b605a060 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Tue, 22 Nov 2016 11:47:50 +0000 Subject: [PATCH 088/305] Coding standards: A local variable may not use the prefix m_ --- .../Avatar/Concierge/ConciergeModule.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs index c4a70c0d57..6c147f4be1 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs @@ -75,14 +75,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge internal new bool m_enabled = false; #region ISharedRegionModule Members - public override void Initialise(IConfigSource config) + public override void Initialise(IConfigSource configSource) { - IConfig m_config = config.Configs["Concierge"]; + IConfig config = configSource.Configs["Concierge"]; - if (null == m_config) + if (config == null) return; - if (!m_config.GetBoolean("enabled", false)) + if (!config.GetBoolean("enabled", false)) return; m_enabled = true; @@ -91,7 +91,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge // then we'll "stand in" try { - if (config.Configs["Chat"] == null) + if (configSource.Configs["Chat"] == null) { // if Chat module has not been configured it's // enabled by default, so we are not going to @@ -100,7 +100,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge } else { - m_replacingChatModule = !config.Configs["Chat"].GetBoolean("enabled", true); + m_replacingChatModule = !configSource.Configs["Chat"].GetBoolean("enabled", true); } } catch (Exception) @@ -111,21 +111,21 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge m_log.InfoFormat("[Concierge] {0} ChatModule", m_replacingChatModule ? "replacing" : "not replacing"); // take note of concierge channel and of identity - m_conciergeChannel = config.Configs["Concierge"].GetInt("concierge_channel", m_conciergeChannel); - m_whoami = m_config.GetString("whoami", "conferencier"); - m_welcomes = m_config.GetString("welcomes", m_welcomes); - m_announceEntering = m_config.GetString("announce_entering", m_announceEntering); - m_announceLeaving = m_config.GetString("announce_leaving", m_announceLeaving); - m_xmlRpcPassword = m_config.GetString("password", m_xmlRpcPassword); - m_brokerURI = m_config.GetString("broker", m_brokerURI); - m_brokerUpdateTimeout = m_config.GetInt("broker_timeout", m_brokerUpdateTimeout); + m_conciergeChannel = configSource.Configs["Concierge"].GetInt("concierge_channel", m_conciergeChannel); + m_whoami = config.GetString("whoami", "conferencier"); + m_welcomes = config.GetString("welcomes", m_welcomes); + m_announceEntering = config.GetString("announce_entering", m_announceEntering); + m_announceLeaving = config.GetString("announce_leaving", m_announceLeaving); + m_xmlRpcPassword = config.GetString("password", m_xmlRpcPassword); + m_brokerURI = config.GetString("broker", m_brokerURI); + m_brokerUpdateTimeout = config.GetInt("broker_timeout", m_brokerUpdateTimeout); m_log.InfoFormat("[Concierge] reporting as \"{0}\" to our users", m_whoami); // calculate regions Regex if (m_regions == null) { - string regions = m_config.GetString("regions", String.Empty); + string regions = config.GetString("regions", String.Empty); if (!String.IsNullOrEmpty(regions)) { m_regions = new Regex(@regions, RegexOptions.Compiled | RegexOptions.IgnoreCase); From 94e48838d5b1f0bf0c5b0e40b7bc9a6f1be156e9 Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Tue, 22 Nov 2016 15:31:45 +0000 Subject: [PATCH 089/305] Include new Region.ini option for DefaultLandingPoint for teleports with no coords specified. This is useful when using a Telehub would be to restrictive as it would block landmarks and map teleports. This location is only ever used when no coordinates are provided. If config value not set, the previous default of 128,128 is used. --- OpenSim/Framework/RegionInfo.cs | 58 +++++++++++++++++++ .../EntityTransfer/EntityTransferModule.cs | 4 ++ .../Region/Framework/Scenes/ScenePresence.cs | 4 ++ bin/Regions/Regions.ini.example | 3 + 4 files changed, 69 insertions(+) diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index ac7735248a..b6e9d9f1f4 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -176,6 +176,9 @@ namespace OpenSim.Framework /// public uint RegionSizeZ = Constants.RegionHeight; + // If entering avatar has no specific coords, this is where they land + public Vector3 DefaultLandingPoint = new Vector3(128, 128, 30); + private Dictionary m_extraSettings = new Dictionary(); // Apparently, we're applying the same estatesettings regardless of whether it's local or remote. @@ -712,6 +715,19 @@ namespace OpenSim.Framework m_regionType = config.GetString("RegionType", String.Empty); allKeys.Remove("RegionType"); + // Get Default Landing Location (Defaults to 128,128) + string temp_location = config.GetString("DefaultLanding", "<128, 128, 30>"); + Vector3 temp_vector; + + if (Vector3.TryParse(temp_location, out temp_vector)) + DefaultLandingPoint = temp_vector; + else + m_log.ErrorFormat("[RegionInfo]: Unable to parse DefaultLanding for '{0}'. The value given was '{1}'", RegionName, temp_location); + + allKeys.Remove("DefaultLanding"); + + DoDefaultLandingSanityChecks(); + #region Prim and map stuff m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0); @@ -764,6 +780,48 @@ namespace OpenSim.Framework } } + // Make sure DefaultLanding is within region borders with a buffer zone 5 meters from borders + private void DoDefaultLandingSanityChecks() + { + // Sanity Check Default Landing + float buffer_zone = 5f; + + bool ValuesCapped = false; + + // Minimum Positions + if (DefaultLandingPoint.X < 0f) + { + DefaultLandingPoint.X = buffer_zone; + ValuesCapped = true; + } + + if (DefaultLandingPoint.Y < 0f) + { + DefaultLandingPoint.Y = buffer_zone; + ValuesCapped = true; + } + + // Maximum Positions + if (DefaultLandingPoint.X > RegionSizeX - buffer_zone) + { + DefaultLandingPoint.X = RegionSizeX - buffer_zone; + ValuesCapped = true; + } + + if (DefaultLandingPoint.Y > RegionSizeY - buffer_zone) + { + DefaultLandingPoint.Y = RegionSizeY - buffer_zone; + ValuesCapped = true; + } + + // Height + if (DefaultLandingPoint.Z < 0f) + DefaultLandingPoint.Z = 0f; + + if (ValuesCapped == true) + m_log.WarnFormat("[RegionInfo]: The default landing location for {0} has been capped to {1}", RegionName, DefaultLandingPoint); + } + // Make sure user specified region sizes are sane. // Must be multiples of legacy region size (256). private void DoRegionSizeSanityChecks() diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 1161571016..23cfde5c43 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -455,6 +455,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer position = emergencyPos; } + // Check Default Location (Also See ScenePresence.CompleteMovement) + if (position.X == 128f && position.Y == 128f) + position = sp.Scene.RegionInfo.DefaultLandingPoint; + // TODO: Get proper AVG Height float localHalfAVHeight = 0.8f; if (sp.Appearance != null) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 7efd9200ed..2cf0e9d3ac 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2043,6 +2043,10 @@ namespace OpenSim.Region.Framework.Scenes look = new Vector3(0.99f, 0.042f, 0); } + // Check Default Location (Also See EntityTransferModule.TeleportAgentWithinRegion) + if (AbsolutePosition.X == 128f && AbsolutePosition.Y == 128f) + AbsolutePosition = Scene.RegionInfo.DefaultLandingPoint; + if (!MakeRootAgent(AbsolutePosition, flying, ref look)) { m_log.DebugFormat( diff --git a/bin/Regions/Regions.ini.example b/bin/Regions/Regions.ini.example index e20fee609b..97d1c4f628 100644 --- a/bin/Regions/Regions.ini.example +++ b/bin/Regions/Regions.ini.example @@ -31,6 +31,9 @@ ExternalHostName = SYSTEMIP ; SizeX = 512 ; SizeY = 512 +; * Default region landing point used when no teleport coords are specified +; DefaultLanding = <128,128,30> + ; * ; * Prim data ; * This allows limiting the sizes of prims and the region prim count From 34d9596f9ba091c98130333e572d0cba8dd4ffeb Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Tue, 22 Nov 2016 15:33:34 +0000 Subject: [PATCH 090/305] Fix typo in a comment --- .../Framework/EntityTransfer/EntityTransferModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 23cfde5c43..33aa7adfc9 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -600,7 +600,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer GridRegion reg; - // handle legacy HG. liked regions are mapped into y = 0 and have no size information + // handle legacy HG. linked regions are mapped into y = 0 and have no size information // so we can only search by base handle if( y == 0) { From 1a6cddf80761deb65773ad344e822ef74a824418 Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Tue, 22 Nov 2016 21:23:01 +0000 Subject: [PATCH 091/305] Minor fix to region default landing point sanity check --- OpenSim/Framework/RegionInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index b6e9d9f1f4..ca17793e64 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -789,13 +789,13 @@ namespace OpenSim.Framework bool ValuesCapped = false; // Minimum Positions - if (DefaultLandingPoint.X < 0f) + if (DefaultLandingPoint.X < buffer_zone) { DefaultLandingPoint.X = buffer_zone; ValuesCapped = true; } - if (DefaultLandingPoint.Y < 0f) + if (DefaultLandingPoint.Y < buffer_zone) { DefaultLandingPoint.Y = buffer_zone; ValuesCapped = true; From f4745e5a354871c5b248d10bb57f40cae5cc788c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 22 Nov 2016 22:24:54 +0000 Subject: [PATCH 092/305] full change ServiceThrottleModule. Let it still service RegionHandleRequest and UUIDNameRequest but this wrong since they are diferent services. Keeping gambling about not having 2 much overlaps of the 2 kind of requests. Remove double thottling of RegionHandleRequest --- .../ClientStack/Linden/UDP/LLClientView.cs | 52 +------ .../ServiceThrottle/ServiceThrottleModule.cs | 140 ++---------------- .../UserManagement/UserManagementModule.cs | 7 +- 3 files changed, 24 insertions(+), 175 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 65a341e274..f472dba9c6 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -9614,61 +9614,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Parcel related packets - // acumulate several HandleRegionHandleRequest consecutive overlaping requests - // to be done with minimal resources as possible - // variables temporary here while in test - - Queue RegionHandleRequests = new Queue(); - bool RegionHandleRequestsInService = false; - private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) { - UUID currentUUID; - RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; - if (handlerRegionHandleRequest == null) - return true; - - RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; - - lock (RegionHandleRequests) + if (handlerRegionHandleRequest != null) { - if (RegionHandleRequestsInService) - { - // we are already busy doing a previus request - // so enqueue it - RegionHandleRequests.Enqueue(rhrPack.RequestBlock.RegionID); - return true; - } - - // else do it - currentUUID = rhrPack.RequestBlock.RegionID; - RegionHandleRequestsInService = true; + RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; + handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); } - while (true) - { - handlerRegionHandleRequest(this, currentUUID); - - lock (RegionHandleRequests) - { - // exit condition, nothing to do or closed - // current code seems to assume we may loose the handler at anytime, - // so keep checking it - handlerRegionHandleRequest = OnRegionHandleRequest; - - if (RegionHandleRequests.Count == 0 || !IsActive || handlerRegionHandleRequest == null) - { - RegionHandleRequests.Clear(); - RegionHandleRequestsInService = false; - return true; - } - currentUUID = RegionHandleRequests.Dequeue(); - } - } - - return true; // actually unreached + return true; } private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs index 3abacbd3cf..36fb57a18d 100644 --- a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -48,31 +48,16 @@ namespace OpenSim.Region.CoreModules.Framework MethodBase.GetCurrentMethod().DeclaringType); private readonly List m_scenes = new List(); - private System.Timers.Timer m_timer = new System.Timers.Timer(); - - private Queue m_RequestQueue = new Queue(); - private Dictionary> m_Pending = new Dictionary>(); - private int m_Interval; - + private JobEngine m_processorJobEngine; + #region ISharedRegionModule public void Initialise(IConfigSource config) { - m_Interval = Util.GetConfigVarFromSections(config, "Interval", new string[] { "ServiceThrottle" }, 5000); - - m_timer = new System.Timers.Timer(); - m_timer.AutoReset = false; - m_timer.Enabled = true; - m_timer.Interval = 15000; // 15 secs at first - m_timer.Elapsed += ProcessQueue; - m_timer.Start(); - - //WorkManager.StartThread( - // ProcessQueue, - // "GridServiceRequestThread", - // ThreadPriority.BelowNormal, - // true, - // false); + m_processorJobEngine = new JobEngine( + "ServiceThrottle","ServiceThrottle"); + m_processorJobEngine.RequestProcessTimeoutOnStop = 31000; // many webrequests have 30s expire + m_processorJobEngine.Start(); } public void AddRegion(Scene scene) @@ -82,7 +67,6 @@ namespace OpenSim.Region.CoreModules.Framework m_scenes.Add(scene); scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; } } @@ -105,6 +89,7 @@ namespace OpenSim.Region.CoreModules.Framework public void Close() { + m_processorJobEngine.Stop(); } public string Name @@ -126,38 +111,24 @@ namespace OpenSim.Region.CoreModules.Framework client.OnRegionHandleRequest += OnRegionHandleRequest; } - void OnMakeRootAgent(ScenePresence obj) - { - lock (m_timer) - { - if (!m_timer.Enabled) - { - m_timer.Interval = m_Interval; - m_timer.Enabled = true; - m_timer.Start(); - } - } - } - public void OnRegionHandleRequest(IClientAPI client, UUID regionID) { //m_log.DebugFormat("[SERVICE THROTTLE]: RegionHandleRequest {0}", regionID); - ulong handle = 0; - if (IsLocalRegionHandle(regionID, out handle)) - { - client.SendRegionHandle(regionID, handle); - return; - } - Action action = delegate { + if(!client.IsActive) + return; + GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, regionID); + if(!client.IsActive) + return; + if (r != null && r.RegionHandle != 0) client.SendRegionHandle(regionID, r.RegionHandle); }; - Enqueue("region", regionID.ToString(), action); + m_processorJobEngine.QueueJob("regionHandle", action, regionID.ToString()); } #endregion Events @@ -166,91 +137,10 @@ namespace OpenSim.Region.CoreModules.Framework public void Enqueue(string category, string itemid, Action continuation) { - lock (m_RequestQueue) - { - if (m_Pending.ContainsKey(category)) - { - if (m_Pending[category].Contains(itemid)) - // Don't enqueue, it's already pending - return; - } - else - m_Pending.Add(category, new List()); - - m_Pending[category].Add(itemid); - - m_RequestQueue.Enqueue(delegate - { - lock (m_RequestQueue) - m_Pending[category].Remove(itemid); - - continuation(); - }); - } + m_processorJobEngine.QueueJob(category, continuation, itemid); } #endregion IServiceThrottleModule - - #region Process Continuation Queue - - private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) - { - //m_log.DebugFormat("[YYY]: Process queue with {0} continuations", m_RequestQueue.Count); - - while (m_RequestQueue.Count > 0) - { - Action continuation = null; - lock (m_RequestQueue) - continuation = m_RequestQueue.Dequeue(); - - if (continuation != null) - continuation(); - } - - if (AreThereRootAgents()) - { - lock (m_timer) - { - m_timer.Interval = 1000; // 1 sec - m_timer.Enabled = true; - m_timer.Start(); - } - } - else - lock (m_timer) - m_timer.Enabled = false; - - } - - #endregion Process Continuation Queue - - #region Misc - - private bool IsLocalRegionHandle(UUID regionID, out ulong regionHandle) - { - regionHandle = 0; - foreach (Scene s in m_scenes) - if (s.RegionInfo.RegionID == regionID) - { - regionHandle = s.RegionInfo.RegionHandle; - return true; - } - return false; - } - - private bool AreThereRootAgents() - { - foreach (Scene s in m_scenes) - { - foreach (ScenePresence sp in s.GetScenePresences()) - if (!sp.IsChildAgent) - return true; - } - - return false; - } - - #endregion Misc } } diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 72fff2290f..5507526310 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -206,7 +206,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } // Not found in cache, queue continuation - m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate + m_ServiceThrottle.Enqueue("uuidname", uuid.ToString(), delegate { //m_log.DebugFormat("[YYY]: Name request {0}", uuid); @@ -216,9 +216,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // So to avoid clients // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will // instead drop the request entirely. + if(!client.IsActive) + return; if (GetUser(uuid, out user)) { - client.SendNameReply(uuid, user.FirstName, user.LastName); + if(client.IsActive) + client.SendNameReply(uuid, user.FirstName, user.LastName); } // else // m_log.DebugFormat( From 59f6353ac1270f8b8967ad515e2f06331f44c295 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 22 Nov 2016 22:29:13 +0000 Subject: [PATCH 093/305] close a resource on jobengine.close() --- OpenSim/Framework/Monitoring/JobEngine.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Framework/Monitoring/JobEngine.cs b/OpenSim/Framework/Monitoring/JobEngine.cs index 7709f629aa..df6b806b4c 100644 --- a/OpenSim/Framework/Monitoring/JobEngine.cs +++ b/OpenSim/Framework/Monitoring/JobEngine.cs @@ -136,7 +136,8 @@ namespace OpenSim.Framework.Monitoring if(m_jobQueue.Count <= 0) m_cancelSource.Cancel(); - m_finishedProcessingAfterStop.WaitOne(RequestProcessTimeoutOnStop); + if(m_finishedProcessingAfterStop.WaitOne(RequestProcessTimeoutOnStop)) + m_finishedProcessingAfterStop.Close(); } finally { From 82ed6bde6e7258ee8380a2e8466d4a7e32c9e5e6 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 23 Nov 2016 10:00:56 +0000 Subject: [PATCH 094/305] fix maturity on parcelInfo --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index f472dba9c6..498d5fe7c0 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -3126,10 +3126,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP reply.Data.ActualArea = land.Area; reply.Data.BillableArea = land.Area; // TODO: what is this? - // Bit 0: Mature, bit 7: on sale, other bits: no idea - reply.Data.Flags = (byte)( - (info.AccessLevel > 13 ? (1 << 0) : 0) + - ((land.Flags & (uint)ParcelFlags.ForSale) != 0 ? (1 << 7) : 0)); + reply.Data.Flags = (byte)Util.ConvertAccessLevelToMaturity((byte)info.AccessLevel); + if((land.Flags & (uint)ParcelFlags.ForSale) != 0) + reply.Data.Flags |= (byte)((1 << 7)); Vector3 pos = land.UserLocation; if (pos.Equals(Vector3.Zero)) From b3eda582ec44ee375a116b91887ddb1bf7c22917 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 23 Nov 2016 19:30:55 +0000 Subject: [PATCH 095/305] add to SynchronousRestFormsRequester a keepalive disable option, and make use of it on some friends conns --- OpenSim/Framework/WebUtil.cs | 15 ++++----------- .../Connectors/Friends/FriendsSimConnector.cs | 2 +- .../Hypergrid/HGFriendsServicesConnector.cs | 5 ++++- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 2bbf785661..f927e6963b 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -1019,7 +1019,8 @@ namespace OpenSim.Framework /// /// Thrown if we encounter a network issue while posting /// the request. You'll want to make sure you deal with this as they're not uncommon - public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs, IServiceAuth auth) + public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs = -1, + IServiceAuth auth = null, bool keepalive = true) { int reqnum = WebUtil.RequestNumber++; @@ -1034,6 +1035,8 @@ namespace OpenSim.Framework request.Method = verb; if (timeoutsecs > 0) request.Timeout = timeoutsecs * 1000; + if(!keepalive && request is HttpWebRequest) + ((HttpWebRequest)request).KeepAlive = false; if (auth != null) auth.AddAuthorization(request.Headers); @@ -1125,16 +1128,6 @@ namespace OpenSim.Framework return respstring; } - public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs) - { - return MakeRequest(verb, requestUrl, obj, timeoutsecs, null); - } - - public static string MakeRequest(string verb, string requestUrl, string obj) - { - return MakeRequest(verb, requestUrl, obj, -1); - } - public static string MakeRequest(string verb, string requestUrl, string obj, IServiceAuth auth) { return MakeRequest(verb, requestUrl, obj, -1, auth); diff --git a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs index 45f4514814..74cd703a35 100644 --- a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs +++ b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs @@ -158,7 +158,7 @@ namespace OpenSim.Services.Connectors.Friends try { - string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString); + string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, 15, null, false); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); diff --git a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs index 622d4e1712..8b31fa2d9d 100644 --- a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs @@ -277,7 +277,10 @@ namespace OpenSim.Services.Connectors.Hypergrid { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - ServerUtils.BuildQueryString(sendData), 15); + ServerUtils.BuildQueryString(sendData), + 15, + null, + false); } catch (Exception e) { From 72e20028d1a5c7bedfcde56429d211d8e427c7a4 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 23 Nov 2016 20:26:14 +0000 Subject: [PATCH 096/305] safeguard against unknown material replacemet --- OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index 006b730074..7312bc39a8 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -532,7 +532,7 @@ namespace OpenSim.Region.OptionalModules.Materials lock(m_Materials) { - if(oldid != UUID.Zero) + if(oldid != UUID.Zero && m_MaterialsRefCount.ContainsKey(oldid)) { m_MaterialsRefCount[oldid]--; if(m_MaterialsRefCount[oldid] <= 0) From d9789596d4db77b086d05f6dd7503a380e468284 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 23 Nov 2016 20:41:10 +0000 Subject: [PATCH 097/305] take parcel_owner_is_god option from ini.example since it is not a recomended option for general use --- bin/OpenSimDefaults.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 35530027ea..3f8864e92f 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -473,7 +473,7 @@ ;region_manager_is_god = false ; Allow parcel owners to assume god powers in their parcels - ; you really may not want this... + ; you really do not want this... ;parcel_owner_is_god = false ; Control user types that are allowed to create new scripts From 75ad210b6bda5c1703c8be191927f9c2baf928c3 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 23 Nov 2016 20:44:55 +0000 Subject: [PATCH 098/305] it is nice to save a file to atually change it... --- bin/OpenSim.ini.example | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 5103e7184d..bb73687cda 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -391,10 +391,6 @@ ;; Allow region managers to assume god powers in regions they manage ; region_manager_is_god = false - ;# {parcel_owner_is_god} {} {Allow parcel owner gods} {true false} false - ;; Allow parcel owners to assume god powers in their parcels - ; parcel_owner_is_god = false - ;# {simple_build_permissions} {} {Allow building in parcel by access list (no groups)} {true false} false ;; More control over permissions ;; This is definitely not SL! From 94ec5884b7d3cfe350725d5734d227fa1becee94 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 23 Nov 2016 22:15:59 +0000 Subject: [PATCH 099/305] fix llRez(AtRoot/Object) error messages on shared code path --- .../ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index af0495119f..3db5dd2820 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -3482,13 +3482,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (item == null) { - Error("llRezAtRoot", "Can't find object '" + inventory + "'"); + Error("llRez(AtRoot/Object)", "Can't find object '" + inventory + "'"); return; } if (item.InvType != (int)InventoryType.Object) { - Error("llRezAtRoot", "Can't create requested object; object is missing from database"); + Error("llRez(AtRoot/Object)", "Can't create requested object; object is missing from database"); return; } @@ -3532,7 +3532,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) } - }, null, "LSL_Api.llRezAtRoot"); + }, null, "LSL_Api.doObjectRez"); //ScriptSleep((int)((groupmass * velmag) / 10)); ScriptSleep(m_sleepMsOnRezAtRoot); From 5202ae7bb4b3e20aad762811195922da6926a54c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 24 Nov 2016 14:39:08 +0000 Subject: [PATCH 100/305] revert changes to asset desc size, my bad.. this field will possible go away in future --- OpenSim/Data/MySQL/MySQLAssetData.cs | 8 -------- OpenSim/Data/MySQL/MySQLXAssetData.cs | 10 +++++----- OpenSim/Data/PGSQL/PGSQLAssetData.cs | 10 +++++----- OpenSim/Data/SQLite/SQLiteAssetData.cs | 10 +++++----- OpenSim/Framework/AssetBase.cs | 16 ++-------------- 5 files changed, 17 insertions(+), 37 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLAssetData.cs b/OpenSim/Data/MySQL/MySQLAssetData.cs index 83e7e4cf3e..1488e1a5bb 100644 --- a/OpenSim/Data/MySQL/MySQLAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLAssetData.cs @@ -170,14 +170,6 @@ namespace OpenSim.Data.MySQL } string assetDescription = asset.Description; - if(assetDescription.Length > AssetBase.MAX_LMASSET_DESC) - { - if(asset.Type == (sbyte) AssetType.Landmark) - assetDescription = assetDescription.Substring(0, AssetBase.MAX_LMASSET_DESC); - else - assetDescription = assetDescription.Substring(0, AssetBase.MAX_ASSET_DESC); - } - if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) { assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); diff --git a/OpenSim/Data/MySQL/MySQLXAssetData.cs b/OpenSim/Data/MySQL/MySQLXAssetData.cs index 6c6f560a4c..ec2bcc69e9 100644 --- a/OpenSim/Data/MySQL/MySQLXAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLXAssetData.cs @@ -214,12 +214,12 @@ namespace OpenSim.Data.MySQL } string assetDescription = asset.Description; - if(assetDescription.Length > AssetBase.MAX_LMASSET_DESC) + if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) { - if(asset.Type == (sbyte) AssetType.Landmark) - assetDescription = assetDescription.Substring(0, AssetBase.MAX_LMASSET_DESC); - else - assetDescription = assetDescription.Substring(0, AssetBase.MAX_ASSET_DESC); + assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); + m_log.WarnFormat( + "[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); } if (m_enableCompression) diff --git a/OpenSim/Data/PGSQL/PGSQLAssetData.cs b/OpenSim/Data/PGSQL/PGSQLAssetData.cs index 97ea6a4ab5..81adb034a9 100644 --- a/OpenSim/Data/PGSQL/PGSQLAssetData.cs +++ b/OpenSim/Data/PGSQL/PGSQLAssetData.cs @@ -175,12 +175,12 @@ namespace OpenSim.Data.PGSQL } string assetDescription = asset.Description; - if(assetDescription.Length > AssetBase.MAX_LMASSET_DESC) + if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) { - if(asset.Type == (sbyte) AssetType.Landmark) - assetDescription = assetDescription.Substring(0, AssetBase.MAX_LMASSET_DESC); - else - assetDescription = assetDescription.Substring(0, AssetBase.MAX_ASSET_DESC); + assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); + m_log.WarnFormat( + "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); } using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) diff --git a/OpenSim/Data/SQLite/SQLiteAssetData.cs b/OpenSim/Data/SQLite/SQLiteAssetData.cs index 9fbd9c7fab..9c2bd2e46e 100644 --- a/OpenSim/Data/SQLite/SQLiteAssetData.cs +++ b/OpenSim/Data/SQLite/SQLiteAssetData.cs @@ -143,12 +143,12 @@ namespace OpenSim.Data.SQLite } string assetDescription = asset.Description; - if(assetDescription.Length > AssetBase.MAX_LMASSET_DESC) + if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) { - if(asset.Type == (sbyte) AssetType.Landmark) - assetDescription = assetDescription.Substring(0, AssetBase.MAX_LMASSET_DESC); - else - assetDescription = assetDescription.Substring(0, AssetBase.MAX_ASSET_DESC); + assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); + m_log.WarnFormat( + "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); } //m_log.Info("[ASSET DB]: Creating Asset " + asset.FullID.ToString()); diff --git a/OpenSim/Framework/AssetBase.cs b/OpenSim/Framework/AssetBase.cs index 67239ec105..87fd04affe 100644 --- a/OpenSim/Framework/AssetBase.cs +++ b/OpenSim/Framework/AssetBase.cs @@ -51,8 +51,7 @@ namespace OpenSim.Framework private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public static readonly int MAX_ASSET_NAME = 64; - public static readonly int MAX_ASSET_DESC = 127; - public static readonly int MAX_LMASSET_DESC = 255; + public static readonly int MAX_ASSET_DESC = 64; /// /// Data of the Asset @@ -306,18 +305,7 @@ namespace OpenSim.Framework public string Description { get { return m_description; } - set - { - if(value.Length > AssetBase.MAX_LMASSET_DESC) - { - if(m_type == (sbyte) AssetType.Landmark) - m_description = value.Substring(0, AssetBase.MAX_LMASSET_DESC); - else - m_description = value.Substring(0, AssetBase.MAX_ASSET_DESC); - } - else - m_description = value; - } + set { m_description = value; } } public DateTime CreationDate From f9b62b5680be1935857e9517b1a6bcd770c7b683 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 24 Nov 2016 20:53:04 +0000 Subject: [PATCH 101/305] work around viewers not suporting large regions on landmark creation. They still may display wrong offset; don't let inventory description be limited by asset description side on a ossl method --- .../World/Land/LandManagementModule.cs | 53 +++++++++++++------ .../Shared/Api/Implementation/OSSL_Api.cs | 4 +- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 11a6d9f745..98f1f3bd44 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -1801,30 +1801,51 @@ namespace OpenSim.Region.CoreModules.World.Land { Hashtable hash = new Hashtable(); hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); - if (hash.ContainsKey("region_id") && hash.ContainsKey("location")) + if (hash.ContainsKey("location")) { - UUID regionID = (UUID)hash["region_id"]; + UUID scope = m_scene.RegionInfo.ScopeID; ArrayList list = (ArrayList)hash["location"]; uint x = (uint)(double)list[0]; uint y = (uint)(double)list[1]; - if (hash.ContainsKey("region_handle")) + if(hash.ContainsKey("region_id")) + { + UUID regionID = (UUID)hash["region_id"]; + if (regionID == m_scene.RegionInfo.RegionID) + { + // a parcel request for a local parcel => no need to query the grid + parcelID = Util.BuildFakeParcelID(m_scene.RegionInfo.RegionHandle, x, y); + } + else + { + // a parcel request for a parcel in another region. Ask the grid about the region + GridRegion info = m_scene.GridService.GetRegionByUUID(scope, regionID); + if (info != null) + parcelID = Util.BuildFakeParcelID(info.RegionHandle, x, y); + } + } + + else if (hash.ContainsKey("region_handle")) { // if you do a "About Landmark" on a landmark a second time, the viewer sends the // region_handle it got earlier via RegionHandleRequest ulong regionHandle = Util.BytesToUInt64Big((byte[])hash["region_handle"]); - parcelID = Util.BuildFakeParcelID(regionHandle, x, y); - } - else if (regionID == m_scene.RegionInfo.RegionID) - { - // a parcel request for a local parcel => no need to query the grid - parcelID = Util.BuildFakeParcelID(m_scene.RegionInfo.RegionHandle, x, y); - } - else - { - // a parcel request for a parcel in another region. Ask the grid about the region - GridRegion info = m_scene.GridService.GetRegionByUUID(UUID.Zero, regionID); - if (info != null) - parcelID = Util.BuildFakeParcelID(info.RegionHandle, x, y); + if(regionHandle == m_scene.RegionInfo.RegionHandle) + parcelID = Util.BuildFakeParcelID(regionHandle, x, y); + else + { + uint wx; + uint wy; + Util.RegionHandleToWorldLoc(regionHandle, out wx, out wy); + wx += x; + wy += y; + GridRegion info = m_scene.GridService.GetRegionByPosition(scope, (int)wx, (int)wy); + if(info != null) + { + wx -= (uint)info.RegionLocX; + wy -= (uint)info.RegionLocY; + parcelID = Util.BuildFakeParcelID(info.RegionHandle, wx, wy); + } + } } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 57bff6e689..1a594e1c35 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -1938,8 +1938,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api taskItem.ResetIDs(m_host.UUID); taskItem.ParentID = m_host.UUID; taskItem.CreationDate = (uint)Util.UnixTimeSinceEpoch(); - taskItem.Name = asset.Name; - taskItem.Description = asset.Description; + taskItem.Name = name; + taskItem.Description = description; taskItem.Type = (int)AssetType.Notecard; taskItem.InvType = (int)InventoryType.Notecard; taskItem.OwnerID = m_host.OwnerID; From e45245d267a91a5f79f0e54351d4e24b8c1690c0 Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Thu, 24 Nov 2016 23:40:20 +0100 Subject: [PATCH 102/305] Implementation of LSL_Integer llScaleByFactor(double scaling_factor) Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- .../Shared/Api/Implementation/LSL_Api.cs | 46 +++++++++++++++++++ .../Shared/Api/Interface/ILSL_Api.cs | 1 + .../Shared/Api/Runtime/LSL_Stub.cs | 5 ++ 3 files changed, 52 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 3db5dd2820..b5abdb597d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -1803,6 +1803,52 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return 0; } + public LSL_Integer llScaleByFactor(double scaling_factor) + { + m_host.AddScriptLPS(1); + SceneObjectGroup group = m_host.ParentGroup; + + if (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical) + return ScriptBaseClass.FALSE; + + if (group.RootPart.KeyframeMotion != null) + return ScriptBaseClass.FALSE; + + List prims = GetLinkParts(ScriptBaseClass.LINK_SET); + if (prims.Count > 0) + { + foreach (SceneObjectPart prim in prims) + { + LSL_Vector size = new LSL_Vector(prim.Scale.X, prim.Scale.Y, prim.Scale.Z); + LSL_Vector new_size = new LSL_Vector(scaling_factor * size); + + new_size.x = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, new_size.x)); + new_size.y = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, new_size.y)); + new_size.z = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, new_size.z)); + + if (new_size.x != scaling_factor * size.x || new_size.y != scaling_factor * size.y || new_size.z != scaling_factor * size.z) + return ScriptBaseClass.FALSE; + + LSL_Vector position = new LSL_Vector(GetPartLocalPos(prim)); + + if (!prim.IsRoot) + { + position = GetSetPosTarget(prim, scaling_factor * position, position, true); + prim.OffsetPosition = position; + prim.ScheduleTerseUpdate(); + } + + SetScale(prim, new_size); + } + + return ScriptBaseClass.TRUE; + } + else + { + return ScriptBaseClass.FALSE; + } + } + public void llSetScale(LSL_Vector scale) { m_host.AddScriptLPS(1); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index 3d1482d921..ea0b6f9dc4 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -326,6 +326,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Integer llRound(double f); LSL_Integer llSameGroup(string agent); void llSay(int channelID, string text); + LSL_Integer llScaleByFactor(double scaling_factor); void llScaleTexture(double u, double v, int face); LSL_Integer llScriptDanger(LSL_Vector pos); void llScriptProfiler(LSL_Integer flag); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 2769712f2a..6aaf93011d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -1465,6 +1465,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llSay(channelID, text); } + public LSL_Integer llScaleByFactor(double scaling_factor) + { + return m_LSL_Functions.llScaleByFactor(scaling_factor); + } + public void llScaleTexture(double u, double v, int face) { m_LSL_Functions.llScaleTexture(u, v, face); From b82a41d2606dfaf42455e0030b5640752167162b Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 25 Nov 2016 17:34:19 +0000 Subject: [PATCH 103/305] change llScaleByFactor (sorry Mandarinka). --- .../Framework/Scenes/SceneObjectGroup.cs | 97 +++++++++++++++++++ .../Shared/Api/Implementation/LSL_Api.cs | 39 ++------ 2 files changed, 106 insertions(+), 30 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 0cd738daa3..739d23d350 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -4161,6 +4161,103 @@ namespace OpenSim.Region.Framework.Scenes } + public bool GroupResize(double fscale) + { +// m_log.DebugFormat( +// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, fscale); + + if (Scene == null || IsDeleted || inTransit || fscale < 0) + return false; + + // ignore lsl restrictions. let them be done a LSL + PhysicsActor pa = m_rootPart.PhysActor; + + if(RootPart.KeyframeMotion != null) + RootPart.KeyframeMotion.Suspend(); + + float minsize = Scene.m_minNonphys; + float maxsize = Scene.m_maxNonphys; + + // assuming physics is more restrictive + if (pa != null && pa.IsPhysical) + { + minsize = Scene.m_minPhys; + maxsize = Scene.m_maxPhys; + } + + SceneObjectPart[] parts = m_parts.GetArray(); + float tmp; + // check scaling factor so parts don't violate dimensions + for(int i = 0; i < parts.Length; i++) + { + SceneObjectPart obPart = parts[i]; + Vector3 oldSize = new Vector3(obPart.Scale); + tmp = (float)(oldSize.X * fscale); + if(tmp > maxsize) + return false; + if(tmp < minsize) + return false; + + tmp = (float)(oldSize.Y * fscale); + if(tmp > maxsize) + return false; + if(tmp < minsize) + return false; + + tmp = (float)(oldSize.Z * fscale); + if(tmp > maxsize) + return false; + if(tmp < minsize) + return false; + } + + Vector3 newSize = RootPart.Scale; + newSize.X = (float)(newSize.X * fscale); + newSize.Y = (float)(newSize.Y * fscale); + newSize.Z = (float)(newSize.Z * fscale); + + if(pa != null) + pa.Building = true; + + RootPart.Scale = newSize; + + Vector3 currentpos; + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart obPart = parts[i]; + + if (obPart.UUID != m_rootPart.UUID) + { + currentpos = obPart.OffsetPosition; + currentpos.X = (float)(currentpos.X * fscale); + currentpos.Y = (float)(currentpos.Y * fscale); + currentpos.Z = (float)(currentpos.Z * fscale); + + newSize = obPart.Scale; + newSize.X = (float)(newSize.X * fscale); + newSize.Y = (float)(newSize.Y * fscale); + newSize.Z = (float)(newSize.Z * fscale); + + obPart.Scale = newSize; + obPart.UpdateOffSet(currentpos); + } + } + + if(pa != null) + pa.Building = false; + + InvalidBoundsRadius(); + + HasGroupChanged = true; + m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); + ScheduleGroupForFullUpdate(); + + if(RootPart.KeyframeMotion != null) + RootPart.KeyframeMotion.Resume(); + + return true; + } + #endregion #region Position diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index b5abdb597d..c43aef58f4 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -1808,45 +1808,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); SceneObjectGroup group = m_host.ParentGroup; + if(scaling_factor < 1e-6) + return ScriptBaseClass.FALSE; + if(scaling_factor > 1e6) + return ScriptBaseClass.FALSE; + + if (group == null || group.IsDeleted || group.inTransit) + return ScriptBaseClass.FALSE; + if (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical) return ScriptBaseClass.FALSE; if (group.RootPart.KeyframeMotion != null) return ScriptBaseClass.FALSE; - List prims = GetLinkParts(ScriptBaseClass.LINK_SET); - if (prims.Count > 0) - { - foreach (SceneObjectPart prim in prims) - { - LSL_Vector size = new LSL_Vector(prim.Scale.X, prim.Scale.Y, prim.Scale.Z); - LSL_Vector new_size = new LSL_Vector(scaling_factor * size); - - new_size.x = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, new_size.x)); - new_size.y = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, new_size.y)); - new_size.z = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, new_size.z)); - - if (new_size.x != scaling_factor * size.x || new_size.y != scaling_factor * size.y || new_size.z != scaling_factor * size.z) - return ScriptBaseClass.FALSE; - - LSL_Vector position = new LSL_Vector(GetPartLocalPos(prim)); - - if (!prim.IsRoot) - { - position = GetSetPosTarget(prim, scaling_factor * position, position, true); - prim.OffsetPosition = position; - prim.ScheduleTerseUpdate(); - } - - SetScale(prim, new_size); - } - + if(group.GroupResize(scaling_factor)) return ScriptBaseClass.TRUE; - } else - { return ScriptBaseClass.FALSE; - } } public void llSetScale(LSL_Vector scale) From 935510d87956f080f1425982b3da918009c32feb Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 25 Nov 2016 18:35:23 +0000 Subject: [PATCH 104/305] add llGetMaxScaleFactor and llGetMinScaleFactor --- .../Framework/Scenes/SceneObjectGroup.cs | 77 +++++++++++++++++++ .../Shared/Api/Implementation/LSL_Api.cs | 22 ++++++ .../Shared/Api/Interface/ILSL_Api.cs | 2 + .../Shared/Api/Runtime/LSL_Stub.cs | 10 +++ 4 files changed, 111 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 739d23d350..6cdbac5e6d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -4258,6 +4258,83 @@ namespace OpenSim.Region.Framework.Scenes return true; } + public float GetMaxGroupResizeScale() + { + if (Scene == null || IsDeleted || inTransit) + return 1.0f; + + float maxsize = Scene.m_maxNonphys; + PhysicsActor pa = m_rootPart.PhysActor; + // assuming physics is more restrictive + if (pa != null && pa.IsPhysical) + maxsize = Scene.m_maxPhys; + + SceneObjectPart[] parts = m_parts.GetArray(); + float larger = float.MinValue; + + for(int i = 0; i < parts.Length; i++) + { + SceneObjectPart obPart = parts[i]; + Vector3 oldSize = new Vector3(obPart.Scale); + if(larger < oldSize.X) + larger = oldSize.X; + + if(larger < oldSize.Y) + larger = oldSize.Y; + + if(larger < oldSize.Z) + larger = oldSize.Z; + } + + if(larger >= maxsize) + return 1.0f; + + larger += 1e-3f; + float fscale = maxsize / larger; + + return fscale; + } + + public float GetMinGroupResizeScale() + { + if (Scene == null || IsDeleted || inTransit) + return 1.0f; + + float minsize = Scene.m_minNonphys; + PhysicsActor pa = m_rootPart.PhysActor; + // assuming physics is more restrictive + if (pa != null && pa.IsPhysical) + minsize = Scene.m_minPhys; + + SceneObjectPart[] parts = m_parts.GetArray(); + float smaller = float.MaxValue; + + for(int i = 0; i < parts.Length; i++) + { + SceneObjectPart obPart = parts[i]; + Vector3 oldSize = new Vector3(obPart.Scale); + if(smaller > oldSize.X) + smaller = oldSize.X; + + if(smaller > oldSize.Y) + smaller = oldSize.Y; + + if(smaller > oldSize.Z) + smaller = oldSize.Z; + } + + if(smaller <= minsize) + return 1.0f; + + if(smaller > 2e-3f) + smaller -= 1e-3f; + float fscale = minsize / smaller; + if(fscale < 1e-8f) + fscale = 1e-8f; + + return fscale; + } + #endregion #region Position diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index c43aef58f4..a9c57898d7 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -1828,6 +1828,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return ScriptBaseClass.FALSE; } + public LSL_Float llGetMaxScaleFactor() + { + m_host.AddScriptLPS(1); + SceneObjectGroup group = m_host.ParentGroup; + + if (group == null || group.IsDeleted || group.inTransit) + return 1.0f; + + return (LSL_Float)group.GetMaxGroupResizeScale(); + } + + public LSL_Float llGetMinScaleFactor() + { + m_host.AddScriptLPS(1); + SceneObjectGroup group = m_host.ParentGroup; + + if (group == null || group.IsDeleted || group.inTransit) + return 1.0f; + + return (LSL_Float)group.GetMinGroupResizeScale(); + } + public void llSetScale(LSL_Vector scale) { m_host.AddScriptLPS(1); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index ea0b6f9dc4..cc5240375c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -327,6 +327,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Integer llSameGroup(string agent); void llSay(int channelID, string text); LSL_Integer llScaleByFactor(double scaling_factor); + LSL_Float llGetMaxScaleFactor(); + LSL_Float llGetMinScaleFactor(); void llScaleTexture(double u, double v, int face); LSL_Integer llScriptDanger(LSL_Vector pos); void llScriptProfiler(LSL_Integer flag); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 6aaf93011d..9d36341947 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -1470,6 +1470,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llScaleByFactor(scaling_factor); } + public LSL_Float llGetMaxScaleFactor() + { + return m_LSL_Functions.llGetMaxScaleFactor(); + } + + public LSL_Float llGetMinScaleFactor() + { + return m_LSL_Functions.llGetMinScaleFactor(); + } + public void llScaleTexture(double u, double v, int face) { m_LSL_Functions.llScaleTexture(u, v, face); From 6f1080368d23d8e3952b5ffd3c3cc05f540d6402 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 25 Nov 2016 21:37:33 +0000 Subject: [PATCH 105/305] reduce the resolution of llGetTime and llGetAndResetTime, to 1ms --- .../Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index a9c57898d7..849d02d7e5 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -3096,7 +3096,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); double ScriptTime = Util.GetTimeStampMS() - m_timer; - return (ScriptTime / 1000.0); + return (float)Math.Round((ScriptTime / 1000.0), 3); } public void llResetTime() @@ -3111,7 +3111,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api double now = Util.GetTimeStampMS(); double ScriptTime = now - m_timer; m_timer = now; - return (ScriptTime / 1000.0); + return (float)Math.Round((ScriptTime / 1000.0), 3); } public void llSound(string sound, double volume, int queue, int loop) From 017069636afd8e0db5a2c81873badcc1f2dc6891 Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Sat, 26 Nov 2016 01:15:10 +0000 Subject: [PATCH 106/305] Increase float precision for windlight needed by scripts. mySQL Migration on regionwindlight table. mySQL was setup to store smaller values because the viewers editor capped input, scripts can set higher precision so settings could change on region restart. This change brings mySQL more inline with PGSQL which uses doubles for all windlight floats. --- .../MySQL/Resources/RegionStore.migrations | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/OpenSim/Data/MySQL/Resources/RegionStore.migrations b/OpenSim/Data/MySQL/Resources/RegionStore.migrations index 1de5a01cfc..edc04b9a5e 100644 --- a/OpenSim/Data/MySQL/Resources/RegionStore.migrations +++ b/OpenSim/Data/MySQL/Resources/RegionStore.migrations @@ -390,3 +390,66 @@ CREATE TABLE IF NOT EXISTS `bakedterrain` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; COMMIT; + +:VERSION 55 #----- Increase float precision for windlight needed by scripts + +BEGIN; + +ALTER TABLE `regionwindlight` + +MODIFY `water_fog_density_exponent` float(9,7) unsigned NOT NULL DEFAULT '4.0', +MODIFY `underwater_fog_modifier` float(9,8) unsigned NOT NULL DEFAULT '0.25', +MODIFY `reflection_wavelet_scale_1` float(9,7) unsigned NOT NULL DEFAULT '2.0', +MODIFY `reflection_wavelet_scale_2` float(9,7) unsigned NOT NULL DEFAULT '2.0', +MODIFY `reflection_wavelet_scale_3` float(9,7) unsigned NOT NULL DEFAULT '2.0', +MODIFY `fresnel_scale` float(9,8) unsigned NOT NULL DEFAULT '0.40', +MODIFY `fresnel_offset` float(9,8) unsigned NOT NULL DEFAULT '0.50', +MODIFY `refract_scale_above` float(9,8) unsigned NOT NULL DEFAULT '0.03', +MODIFY `refract_scale_below` float(9,8) unsigned NOT NULL DEFAULT '0.20', +MODIFY `blur_multiplier` float(9,8) unsigned NOT NULL DEFAULT '0.040', +MODIFY `big_wave_direction_x` float(9,8) NOT NULL DEFAULT '1.05', +MODIFY `big_wave_direction_y` float(9,8) NOT NULL DEFAULT '-0.42', +MODIFY `little_wave_direction_x` float(9,8) NOT NULL DEFAULT '1.11', +MODIFY `little_wave_direction_y` float(9,8) NOT NULL DEFAULT '-1.16', +MODIFY `horizon_r` float(9,8) unsigned NOT NULL DEFAULT '0.25', +MODIFY `horizon_g` float(9,8) unsigned NOT NULL DEFAULT '0.25', +MODIFY `horizon_b` float(9,8) unsigned NOT NULL DEFAULT '0.32', +MODIFY `horizon_i` float(9,8) unsigned NOT NULL DEFAULT '0.32', +MODIFY `haze_horizon` float(9,8) unsigned NOT NULL DEFAULT '0.19', +MODIFY `blue_density_r` float(9,8) unsigned NOT NULL DEFAULT '0.12', +MODIFY `blue_density_g` float(9,8) unsigned NOT NULL DEFAULT '0.22', +MODIFY `blue_density_b` float(9,8) unsigned NOT NULL DEFAULT '0.38', +MODIFY `blue_density_i` float(9,8) unsigned NOT NULL DEFAULT '0.38', +MODIFY `haze_density` float(9,8) unsigned NOT NULL DEFAULT '0.70', +MODIFY `density_multiplier` float(9,8) unsigned NOT NULL DEFAULT '0.18', +MODIFY `distance_multiplier` float(9,6) unsigned NOT NULL DEFAULT '0.8', +MODIFY `sun_moon_color_r` float(9,8) unsigned NOT NULL DEFAULT '0.24', +MODIFY `sun_moon_color_g` float(9,8) unsigned NOT NULL DEFAULT '0.26', +MODIFY `sun_moon_color_b` float(9,8) unsigned NOT NULL DEFAULT '0.30', +MODIFY `sun_moon_color_i` float(9,8) unsigned NOT NULL DEFAULT '0.30', +MODIFY `sun_moon_position` float(9,8) unsigned NOT NULL DEFAULT '0.317', +MODIFY `ambient_r` float(9,8) unsigned NOT NULL DEFAULT '0.35', +MODIFY `ambient_g` float(9,8) unsigned NOT NULL DEFAULT '0.35', +MODIFY `ambient_b` float(9,8) unsigned NOT NULL DEFAULT '0.35', +MODIFY `ambient_i` float(9,8) unsigned NOT NULL DEFAULT '0.35', +MODIFY `east_angle` float(9,8) unsigned NOT NULL DEFAULT '0.00', +MODIFY `sun_glow_focus` float(9,8) unsigned NOT NULL DEFAULT '0.10', +MODIFY `sun_glow_size` float(9,8) unsigned NOT NULL DEFAULT '1.75', +MODIFY `scene_gamma` float(9,7) unsigned NOT NULL DEFAULT '1.00', +MODIFY `star_brightness` float(9,8) unsigned NOT NULL DEFAULT '0.00', +MODIFY `cloud_color_r` float(9,8) unsigned NOT NULL DEFAULT '0.41', +MODIFY `cloud_color_g` float(9,8) unsigned NOT NULL DEFAULT '0.41', +MODIFY `cloud_color_b` float(9,8) unsigned NOT NULL DEFAULT '0.41', +MODIFY `cloud_color_i` float(9,8) unsigned NOT NULL DEFAULT '0.41', +MODIFY `cloud_x` float(9,8) unsigned NOT NULL DEFAULT '1.00', +MODIFY `cloud_y` float(9,8) unsigned NOT NULL DEFAULT '0.53', +MODIFY `cloud_density` float(9,8) unsigned NOT NULL DEFAULT '1.00', +MODIFY `cloud_coverage` float(9,8) unsigned NOT NULL DEFAULT '0.27', +MODIFY `cloud_scale` float(9,8) unsigned NOT NULL DEFAULT '0.42', +MODIFY `cloud_detail_x` float(9,8) unsigned NOT NULL DEFAULT '1.00', +MODIFY `cloud_detail_y` float(9,8) unsigned NOT NULL DEFAULT '0.53', +MODIFY `cloud_detail_density` float(9,8) unsigned NOT NULL DEFAULT '0.12', +MODIFY `cloud_scroll_x` float(9,7) NOT NULL DEFAULT '0.20', +MODIFY `cloud_scroll_y` float(9,7) NOT NULL DEFAULT '0.01'; + +COMMIT; From e60366ce92e9166e75198e555cd8571e1cd3ec6d Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 26 Nov 2016 03:29:22 +0000 Subject: [PATCH 107/305] avoid doing unnecessary heavy things on change physics rep --- OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs b/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs index 60b24ec891..a50905b839 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODEPrim.cs @@ -2969,6 +2969,13 @@ namespace OpenSim.Region.PhysicsModule.ubOde private void changePhysRepData(ODEPhysRepData repData) { + if(_size == repData.size && + _pbs == repData.pbs && + m_shapetype == repData.shapetype && + m_mesh == repData.mesh && + primVolume == repData.volume) + return; + CheckDelaySelect(); OdePrim parent = (OdePrim)_parent; From 019910afbdd76a907a7fe3a5c7b9044fae17f4d2 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 26 Nov 2016 03:57:33 +0000 Subject: [PATCH 108/305] don't go seach for info we already have at hand.. and there is no region height on osGetRegionSize --- .../ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 1a594e1c35..a21a0caa4e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -3354,8 +3354,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); Scene scene = m_ScriptEngine.World; - GridRegion region = scene.GridService.GetRegionByUUID(UUID.Zero, World.RegionInfo.RegionID); - return new LSL_Vector((float)region.RegionSizeX, (float)region.RegionSizeY, (float)Constants.RegionHeight); + RegionInfo reg = World.RegionInfo; +// GridRegion region = scene.GridService.GetRegionByUUID(UUID.Zero, World.RegionInfo.RegionID); +// return new LSL_Vector((float)region.RegionSizeX, (float)region.RegionSizeY, (float)Constants.RegionHeight); + return new LSL_Vector((float)reg.RegionSizeX, (float)reg.RegionSizeY, 0.0f); } public int osGetSimulatorMemory() From 1e90417ac2edd53a0ece0d69e46750249953791f Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Fri, 25 Nov 2016 06:45:57 +0100 Subject: [PATCH 109/305] Fix in descriptions of: load xml, load xml2, save xml, save xml2 Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- OpenSim/Region/Application/OpenSim.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 4ab48e31be..5d21368cca 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -242,22 +242,22 @@ namespace OpenSim ChangeSelectedRegion); m_console.Commands.AddCommand("Archiving", false, "save xml", - "save xml", + "save xml []", "Save a region's data in XML format", SaveXml); m_console.Commands.AddCommand("Archiving", false, "save xml2", - "save xml2", + "save xml2 []", "Save a region's data in XML2 format", SaveXml2); m_console.Commands.AddCommand("Archiving", false, "load xml", - "load xml [-newIDs [ ]]", + "load xml [ [-newUID [ ]]]", "Load a region's data from XML format", LoadXml); m_console.Commands.AddCommand("Archiving", false, "load xml2", - "load xml2", + "load xml2 []", "Load a region's data from XML2 format", LoadXml2); From d2bbd7ef2b31e84099ac401d88fc2a3193d81ed6 Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Fri, 25 Nov 2016 06:51:16 +0100 Subject: [PATCH 110/305] Fix in cmdparams.Length for: SavePrimsXml2 and SaveXml Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- OpenSim/Region/Application/OpenSim.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 5d21368cca..cf2bf33231 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -1068,7 +1068,7 @@ namespace OpenSim /// protected void SavePrimsXml2(string module, string[] cmdparams) { - if (cmdparams.Length > 5) + if (cmdparams.Length > 4) { SceneManager.SaveNamedPrimsToXml2(cmdparams[3], cmdparams[4]); } @@ -1087,7 +1087,7 @@ namespace OpenSim { MainConsole.Instance.Output("PLEASE NOTE, save-xml is DEPRECATED and may be REMOVED soon. If you are using this and there is some reason you can't use save-xml2, please file a mantis detailing the reason."); - if (cmdparams.Length > 0) + if (cmdparams.Length > 2) { SceneManager.SaveCurrentSceneToXml(cmdparams[2]); } From b781de73e31b22930a687cd541e48cd1aabfb908 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 26 Nov 2016 04:49:35 +0000 Subject: [PATCH 111/305] mantis 7656, partialy apply patch, changing the start scripts for now --- OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs index 3c03130bd2..01bc491566 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs @@ -265,6 +265,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization foreach (XmlNode aPrimNode in rootNode.ChildNodes) { SceneObjectGroup obj = DeserializeGroupFromXml2(aPrimNode.OuterXml); + scene.AddNewSceneObject(obj, true); if (startScripts) sceneObjects.Add(obj); } From 5cc0d6620de4dd5c5b532ee284c8f873d0342ecb Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 26 Nov 2016 05:08:46 +0000 Subject: [PATCH 112/305] remove 2 more null refs i added to release memory --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 498d5fe7c0..6cdf6f635d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -615,8 +615,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP ImageManager.Close(); ImageManager = null; - m_entityUpdates = null; - m_entityProps = null; + m_entityUpdates = new PriorityQueue(1); + m_entityProps = new PriorityQueue(1); m_killRecord.Clear(); GroupsInView.Clear(); // m_scene = null; can't do this unless checks are added everywhere due to workitems already in pools From 155f8dac1d894b6323197893fa5dc3d61823786d Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 27 Nov 2016 02:12:12 +0000 Subject: [PATCH 113/305] BUG fix encoding or region size on HG LinkRegionRequest response --- OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs index cb15138465..2d0b2b68f5 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs @@ -79,8 +79,8 @@ namespace OpenSim.Server.Handlers.Hypergrid hash["result"] = success.ToString(); hash["uuid"] = regionID.ToString(); hash["handle"] = regionHandle.ToString(); - hash["size_x"] = sizeX; - hash["size_y"] = sizeY; + hash["size_x"] = sizeX.ToString(); + hash["size_y"] = sizeY.ToString(); hash["region_image"] = imageURL; hash["external_name"] = externalName; From d3cd323f0c5826c3162965a536645abaa5b30f04 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 27 Nov 2016 15:07:14 +0000 Subject: [PATCH 114/305] HG on links request build the URI in http format with a / at end, this should not be needed but is coerent with current serverURI --- OpenSim/Services/GridService/HypergridLinker.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs index 3b85160df9..28693499a2 100644 --- a/OpenSim/Services/GridService/HypergridLinker.cs +++ b/OpenSim/Services/GridService/HypergridLinker.cs @@ -231,9 +231,10 @@ namespace OpenSim.Services.GridService { regionName = parts[2]; } - - bool success = TryCreateLink(scopeID, xloc, yloc, regionName, port, host, ownerID, out regInfo, out reason); - if (success) + + string serverURI = "http://"+ host +":"+ port.ToString() + "/"; +// bool success = TryCreateLink(scopeID, xloc, yloc, regionName, port, host, ownerID, out regInfo, out reason); + if(TryCreateLink(scopeID, xloc, yloc, regionName, 0, null, serverURI, ownerID, out regInfo, out reason)) { regInfo.RegionName = mapName; return regInfo; @@ -257,6 +258,8 @@ namespace OpenSim.Services.GridService } serverURI = parts[0]; + if (!serverURI.EndsWith("/")) + serverURI = serverURI + "/"; if (parts.Length >= 2) { From 1aa4dbdb3fd5c3c8382dad53d6b7c105fb7cec85 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 28 Nov 2016 04:29:57 +0000 Subject: [PATCH 115/305] increase HG mapsearch spargetti; add more flexibility on input uri formats. To find regions in memory for a grid the http format needs to be used, because aditional compares made by viewers --- .../World/WorldMap/MapSearchModule.cs | 162 +++++++++--------- OpenSim/Services/GridService/GridService.cs | 87 +++++++++- .../Services/GridService/HypergridLinker.cs | 150 ++++++++++------ 3 files changed, 259 insertions(+), 140 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index 73701560de..b1234fec28 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs @@ -128,104 +128,104 @@ namespace OpenSim.Region.CoreModules.World.WorldMap m_Clients.Add(remoteClient.AgentId); } - try - { - OnMapNameRequest(remoteClient, mapName, flags); - } - finally - { - lock (m_Clients) - m_Clients.Remove(remoteClient.AgentId); - } + OnMapNameRequest(remoteClient, mapName, flags); } private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) { Util.FireAndForget(x => { - List blocks = new List(); - if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4)) + try { + List blocks = new List(); + if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4)) + { + // final block, closing the search result + AddFinalBlock(blocks,mapName); + + // flags are agent flags sent from the viewer. + // they have different values depending on different viewers, apparently + remoteClient.SendMapBlock(blocks, flags); + remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); + return; + } + + //m_log.DebugFormat("MAP NAME=({0})", mapName); + + // Hack to get around the fact that ll V3 now drops the port from the + // map name. See https://jira.secondlife.com/browse/VWR-28570 + // + // Caller, use this magic form instead: + // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 + // or url encode if possible. + // the hacks we do with this viewer... + // + bool needOriginalName = false; + string mapNameOrig = mapName; + if (mapName.Contains("|")) + { + mapName = mapName.Replace('|', ':'); + needOriginalName = true; + } + if (mapName.Contains("+")) + { + mapName = mapName.Replace('+', ' '); + needOriginalName = true; + } + if (mapName.Contains("!")) + { + mapName = mapName.Replace('!', '/'); + needOriginalName = true; + } + if (mapName.Contains(".")) + needOriginalName = true; + + // try to fetch from GridServer + List regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); + // if (regionInfos.Count == 0) + // remoteClient.SendAlertMessage("Hyperlink could not be established."); + + //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); + + MapBlockData data; + if (regionInfos.Count > 0) + { + foreach (GridRegion info in regionInfos) + { + data = new MapBlockData(); + data.Agents = 0; + data.Access = info.Access; + MapBlockData block = new MapBlockData(); + WorldMap.MapBlockFromGridRegion(block, info, flags); + + if (flags == 2 && regionInfos.Count == 1 && needOriginalName) + block.Name = mapNameOrig; + blocks.Add(block); + } + } + // final block, closing the search result - AddFinalBlock(blocks,mapName); + AddFinalBlock(blocks,mapNameOrig); // flags are agent flags sent from the viewer. // they have different values depending on different viewers, apparently remoteClient.SendMapBlock(blocks, flags); - remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); - return; - } - //m_log.DebugFormat("MAP NAME=({0})", mapName); - - // Hack to get around the fact that ll V3 now drops the port from the - // map name. See https://jira.secondlife.com/browse/VWR-28570 - // - // Caller, use this magic form instead: - // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 - // or url encode if possible. - // the hacks we do with this viewer... - // - bool needOriginalName = false; - string mapNameOrig = mapName; - if (mapName.Contains("|")) - { - mapName = mapName.Replace('|', ':'); - needOriginalName = true; - } - if (mapName.Contains("+")) - { - mapName = mapName.Replace('+', ' '); - needOriginalName = true; - } - if (mapName.Contains("!")) - { - mapName = mapName.Replace('!', '/'); - needOriginalName = true; - } - if (mapName.Contains(".")) - needOriginalName = true; - - // try to fetch from GridServer - List regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); - // if (regionInfos.Count == 0) - // remoteClient.SendAlertMessage("Hyperlink could not be established."); - - //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); - - MapBlockData data; - if (regionInfos.Count > 0) - { - foreach (GridRegion info in regionInfos) + // send extra user messages for V3 + // because the UI is very confusing + // while we don't fix the hard-coded urls + if (flags == 2) { - data = new MapBlockData(); - data.Agents = 0; - data.Access = info.Access; - MapBlockData block = new MapBlockData(); - WorldMap.MapBlockFromGridRegion(block, info, flags); - - if (flags == 2 && regionInfos.Count == 1 && needOriginalName) - block.Name = mapNameOrig; - blocks.Add(block); + if (regionInfos.Count == 0) + remoteClient.SendAgentAlertMessage("No regions found with that name.", true); + // else if (regionInfos.Count == 1) + // remoteClient.SendAgentAlertMessage("Region found!", false); } } - - // final block, closing the search result - AddFinalBlock(blocks,mapNameOrig); - - // flags are agent flags sent from the viewer. - // they have different values depending on different viewers, apparently - remoteClient.SendMapBlock(blocks, flags); - - // send extra user messages for V3 - // because the UI is very confusing - // while we don't fix the hard-coded urls - if (flags == 2) + finally { - if (regionInfos.Count == 0) - remoteClient.SendAgentAlertMessage("No regions found with that name.", true); -// else if (regionInfos.Count == 1) -// remoteClient.SendAgentAlertMessage("Region found!", false); + lock (m_Clients) + m_Clients.Remove(remoteClient.AgentId); } }); } diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index a11cae1c4b..66c918f9e3 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -579,7 +579,70 @@ namespace OpenSim.Services.GridService int count = 0; List rinfos = new List(); - if (rdatas != null) + if (count < maxNumber && m_AllowHypergridMapSearch && name.Contains(".")) + { + string regionURI = ""; + string regionName = ""; + if(!m_HypergridLinker.buildHGRegionURI(name, out regionURI, out regionName)) + return null; + + string mapname = regionURI + regionName; + bool haveMatch = false; + + if (rdatas != null && (rdatas.Count > 0)) + { +// m_log.DebugFormat("[GRID SERVICE]: Found {0} regions", rdatas.Count); + foreach (RegionData rdata in rdatas) + { + if (count++ < maxNumber) + rinfos.Add(RegionData2RegionInfo(rdata)); + if(rdata.RegionName == mapname) + { + haveMatch = true; + if(count == maxNumber) + { + rinfos.RemoveAt(count - 1); + rinfos.Add(RegionData2RegionInfo(rdata)); + } + } + } + if(haveMatch) + return rinfos; + } + + rdatas = m_Database.Get(Util.EscapeForLike(mapname)+ "%", scopeID); + if (rdatas != null && (rdatas.Count > 0)) + { +// m_log.DebugFormat("[GRID SERVICE]: Found {0} regions", rdatas.Count); + foreach (RegionData rdata in rdatas) + { + if (count++ < maxNumber) + rinfos.Add(RegionData2RegionInfo(rdata)); + if(rdata.RegionName == mapname) + { + haveMatch = true; + if(count == maxNumber) + { + rinfos.RemoveAt(count - 1); + rinfos.Add(RegionData2RegionInfo(rdata)); + break; + } + } + } + if(haveMatch) + return rinfos; + } + + string HGname = regionURI +" "+ regionName; + GridRegion r = m_HypergridLinker.LinkRegion(scopeID, HGname); + if (r != null) + { + if( count == maxNumber) + rinfos.RemoveAt(count - 1); + rinfos.Add(r); + } + } + else if (rdatas != null && (rdatas.Count > 0)) { // m_log.DebugFormat("[GRID SERVICE]: Found {0} regions", rdatas.Count); foreach (RegionData rdata in rdatas) @@ -589,13 +652,6 @@ namespace OpenSim.Services.GridService } } - if (m_AllowHypergridMapSearch && (rdatas == null || (rdatas != null && rdatas.Count == 0))) - { - GridRegion r = GetHypergridRegionByName(scopeID, name); - if (r != null) - rinfos.Add(r); - } - return rinfos; } @@ -608,7 +664,20 @@ namespace OpenSim.Services.GridService protected GridRegion GetHypergridRegionByName(UUID scopeID, string name) { if (name.Contains(".")) - return m_HypergridLinker.LinkRegion(scopeID, name); + { + string regionURI = ""; + string regionName = ""; + if(!m_HypergridLinker.buildHGRegionURI(name, out regionURI, out regionName)) + return null; + + string mapname = regionURI + regionName; + List rdatas = m_Database.Get(Util.EscapeForLike(mapname), scopeID); + if ((rdatas != null) && (rdatas.Count > 0)) + return RegionData2RegionInfo(rdatas[0]); // get the first + + string HGname = regionURI +" "+ regionName; + return m_HypergridLinker.LinkRegion(scopeID, HGname); + } else return null; } diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs index 28693499a2..e00025bfef 100644 --- a/OpenSim/Services/GridService/HypergridLinker.cs +++ b/OpenSim/Services/GridService/HypergridLinker.cs @@ -191,14 +191,14 @@ namespace OpenSim.Services.GridService return TryLinkRegionToCoords(scopeID, mapName, xloc, yloc, UUID.Zero, out reason); } - public GridRegion TryLinkRegionToCoords(UUID scopeID, string mapName, int xloc, int yloc, UUID ownerID, out string reason) + public bool buildHGRegionURI(string inputName, out string serverURI, out string regionName) { - reason = string.Empty; - GridRegion regInfo = null; + serverURI = string.Empty; + regionName = string.Empty; - mapName = mapName.Trim(); + inputName = inputName.Trim(); - if (!mapName.StartsWith("http") && !mapName.StartsWith("https")) + if (!inputName.StartsWith("http") && !inputName.StartsWith("https")) { // Formats: grid.example.com:8002:region name // grid.example.com:region name @@ -207,38 +207,59 @@ namespace OpenSim.Services.GridService string host; uint port = 80; - string regionName = ""; - string[] parts = mapName.Split(new char[] { ':' }); - - if (parts.Length == 0) + string[] parts = inputName.Split(new char[] { ':' }); + int indx; + if(parts.Length == 0) + return false; + if (parts.Length == 1) { - reason = "Wrong format for link-region"; - return null; + indx = inputName.IndexOf('/'); + if (indx < 0) + serverURI = "http://"+ inputName + "/"; + else + { + serverURI = "http://"+ inputName.Substring(0,indx + 1); + if(indx + 2 < inputName.Length) + regionName = inputName.Substring(indx + 1); + } } - - host = parts[0]; - - if (parts.Length >= 2) + else { - // If it's a number then assume it's a port. Otherwise, it's a region name. - if (!UInt32.TryParse(parts[1], out port)) - regionName = parts[1]; - } + host = parts[0]; + + if (parts.Length >= 2) + { + indx = parts[1].IndexOf('/'); + if(indx < 0) + { + // If it's a number then assume it's a port. Otherwise, it's a region name. + if (!UInt32.TryParse(parts[1], out port)) + { + port = 80; + regionName = parts[1]; + } + } + else + { + string portstr = parts[1].Substring(0, indx); + if(indx + 2 < parts[1].Length) + regionName = parts[1].Substring(indx + 1); + if (!UInt32.TryParse(portstr, out port)) + port = 80; + } + } + // always take the last one + if (parts.Length >= 3) + { + regionName = parts[2]; + } - // always take the last one - if (parts.Length >= 3) - { - regionName = parts[2]; - } - - string serverURI = "http://"+ host +":"+ port.ToString() + "/"; -// bool success = TryCreateLink(scopeID, xloc, yloc, regionName, port, host, ownerID, out regInfo, out reason); - if(TryCreateLink(scopeID, xloc, yloc, regionName, 0, null, serverURI, ownerID, out regInfo, out reason)) - { - regInfo.RegionName = mapName; - return regInfo; - } + if(port == 80) + serverURI = "http://"+ host + "/"; + else + serverURI = "http://"+ host +":"+ port.ToString() + "/"; + } } else { @@ -246,32 +267,61 @@ namespace OpenSim.Services.GridService // http://grid.example.com "region name" // http://grid.example.com - string serverURI; - string regionName = ""; - - string[] parts = mapName.Split(new char[] { ' ' }); + string[] parts = inputName.Split(new char[] { ' ' }); if (parts.Length == 0) - { - reason = "Wrong format for link-region"; - return null; - } + return false; serverURI = parts[0]; - if (!serverURI.EndsWith("/")) - serverURI = serverURI + "/"; - if (parts.Length >= 2) + int indx = serverURI.LastIndexOf('/'); + if(indx > 10) { - regionName = mapName.Substring(serverURI.Length); - regionName = regionName.Trim(new char[] { '"', ' ' }); + if(indx + 2 < inputName.Length) + regionName = inputName.Substring(indx + 1); + serverURI = inputName.Substring(0, indx + 1); } + else if (parts.Length >= 2) + { + regionName = inputName.Substring(serverURI.Length); + } + } - if (TryCreateLink(scopeID, xloc, yloc, regionName, 0, null, serverURI, ownerID, out regInfo, out reason)) - { - regInfo.RegionName = mapName; - return regInfo; - } + // use better code for sanity check + Uri uri; + try + { + uri = new Uri(serverURI); + } + catch + { + return false; + } + + if(!string.IsNullOrEmpty(regionName)) + regionName = regionName.Trim(new char[] { '"', ' ' }); + serverURI = uri.AbsoluteUri; + return true; + } + + public GridRegion TryLinkRegionToCoords(UUID scopeID, string mapName, int xloc, int yloc, UUID ownerID, out string reason) + { + reason = string.Empty; + GridRegion regInfo = null; + + string serverURI = string.Empty; + string regionName = string.Empty; + + if(!buildHGRegionURI(mapName, out serverURI, out regionName)) + { + reason = "Wrong URI format for link-region"; + return null; + } + + if (TryCreateLink(scopeID, xloc, yloc, regionName, 0, null, serverURI, ownerID, out regInfo, out reason)) + { + regInfo.RegionName = serverURI + regionName; + return regInfo; } return null; From af3f2717fd1b92a0f5f6003a8ce03939b8c57b47 Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Sun, 27 Nov 2016 22:50:11 +0100 Subject: [PATCH 116/305] The implementation of new flags = paramters for llGetObjectDetails - Part I Constant: integer OBJECT_CLICK_ACTION = 28; Constant: integer OBJECT_OMEGA = 29; Constant: integer OBJECT_PRIM_COUNT = 30; Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- .../Shared/Api/Implementation/LSL_Api.cs | 23 +++++++++++++++++++ .../Shared/Api/Runtime/LSL_Constants.cs | 3 +++ 2 files changed, 26 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 849d02d7e5..cc36ad1d9f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -13758,6 +13758,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_LAST_OWNER_ID: ret.Add(new LSL_Key(ScriptBaseClass.NULL_KEY)); break; + case ScriptBaseClass.OBJECT_CLICK_ACTION: + ret.Add(new LSL_Integer(0)); + break; + case ScriptBaseClass.OBJECT_OMEGA: + ret.Add(new LSL_Vector(Vector3.Zero)); + break; + case ScriptBaseClass.OBJECT_PRIM_COUNT: + LSL_List AttachmentsPrimList = new LSL_List(); + List Attachments; + Attachments = av.GetAttachments(); + foreach (SceneObjectGroup Attachment in Attachments) + AttachmentsPrimList.Add(new LSL_Integer(Attachment.PrimCount)); + ret.Add(new LSL_Integer(AttachmentsPrimList.Sum())); + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); @@ -13930,6 +13944,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_LAST_OWNER_ID: ret.Add(new LSL_Key(obj.ParentGroup.LastOwnerID.ToString())); break; + case ScriptBaseClass.OBJECT_CLICK_ACTION: + ret.Add(new LSL_Integer(obj.ClickAction)); + break; + case ScriptBaseClass.OBJECT_OMEGA: + ret.Add(new LSL_Vector(obj.AngularVelocity)); + break; + case ScriptBaseClass.OBJECT_PRIM_COUNT: + ret.Add(new LSL_Integer(obj.ParentGroup.PrimCount)); + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index cee66b277a..a177310b1d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -636,6 +636,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OBJECT_HOVER_HEIGHT = 25; public const int OBJECT_BODY_SHAPE_TYPE = 26; public const int OBJECT_LAST_OWNER_ID = 27; + public const int OBJECT_CLICK_ACTION = 28; + public const int OBJECT_OMEGA = 29; + public const int OBJECT_PRIM_COUNT = 30; // Pathfinding types public const int OPT_OTHER = -1; From 0bb959d8fda598b0f166ba5131a493c64147a317 Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Mon, 28 Nov 2016 05:05:36 +0100 Subject: [PATCH 117/305] The implementation of new flags = parameters for llGetObjectDetails - Part II Constant: integer OBJECT_TOTAL_INVENTORY_COUNT = 31 Constant: integer OBJECT_GROUP_TAG = 33 Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- .../Shared/Api/Implementation/LSL_Api.cs | 25 +++++++++++++++++++ .../Shared/Api/Runtime/LSL_Constants.cs | 2 ++ 2 files changed, 27 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index cc36ad1d9f..d90d5ddeca 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -13772,6 +13772,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api AttachmentsPrimList.Add(new LSL_Integer(Attachment.PrimCount)); ret.Add(new LSL_Integer(AttachmentsPrimList.Sum())); break; + case ScriptBaseClass.OBJECT_TOTAL_INVENTORY_COUNT: + LSL_List AttachmentsPrimsInventoryList = new LSL_List(); + foreach (SceneObjectGroup Attachment in av.GetAttachments()) + { + Attachment.ForEachPart(delegate(SceneObjectPart part) + { + AttachmentsPrimsInventoryList.Add(new LSL_Integer(part.Inventory.Count)); + }); + } + ret.Add(new LSL_Integer(AttachmentsPrimsInventoryList.Sum())); + break; + case ScriptBaseClass.OBJECT_GROUP_TAG: + ret.Add(new LSL_String(av.Grouptitle)); + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); @@ -13953,6 +13967,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_PRIM_COUNT: ret.Add(new LSL_Integer(obj.ParentGroup.PrimCount)); break; + case ScriptBaseClass.OBJECT_TOTAL_INVENTORY_COUNT: + LSL_List ObjectPrimsInventoryList = new LSL_List(); + obj.ParentGroup.ForEachPart(delegate(SceneObjectPart part) + { + ObjectPrimsInventoryList.Add(new LSL_Integer(part.Inventory.Count)); + }); + ret.Add(ObjectPrimsInventoryList.Sum()); + break; + case ScriptBaseClass.OBJECT_GROUP_TAG: + ret.Add(new LSL_String(String.Empty)); + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index a177310b1d..17173a2444 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -639,6 +639,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OBJECT_CLICK_ACTION = 28; public const int OBJECT_OMEGA = 29; public const int OBJECT_PRIM_COUNT = 30; + public const int OBJECT_TOTAL_INVENTORY_COUNT = 31; + public const int OBJECT_GROUP_TAG = 33; // Pathfinding types public const int OPT_OTHER = -1; From 9dd820765eaa51d7583abcf493e203f575036d5f Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 28 Nov 2016 05:58:05 +0000 Subject: [PATCH 118/305] change last patch a bit --- .../Shared/Api/Implementation/LSL_Api.cs | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index d90d5ddeca..80bb461746 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -13765,23 +13765,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ret.Add(new LSL_Vector(Vector3.Zero)); break; case ScriptBaseClass.OBJECT_PRIM_COUNT: - LSL_List AttachmentsPrimList = new LSL_List(); - List Attachments; - Attachments = av.GetAttachments(); - foreach (SceneObjectGroup Attachment in Attachments) - AttachmentsPrimList.Add(new LSL_Integer(Attachment.PrimCount)); - ret.Add(new LSL_Integer(AttachmentsPrimList.Sum())); + List Attachments = av.GetAttachments(); + int count = 0; + try + { + foreach (SceneObjectGroup Attachment in Attachments) + count += Attachment.PrimCount; + } catch { }; + ret.Add(new LSL_Integer(count)); break; case ScriptBaseClass.OBJECT_TOTAL_INVENTORY_COUNT: - LSL_List AttachmentsPrimsInventoryList = new LSL_List(); - foreach (SceneObjectGroup Attachment in av.GetAttachments()) + List invAttachments = av.GetAttachments(); + int invcount = 0; + try { - Attachment.ForEachPart(delegate(SceneObjectPart part) + foreach (SceneObjectGroup Attachment in invAttachments) { - AttachmentsPrimsInventoryList.Add(new LSL_Integer(part.Inventory.Count)); - }); - } - ret.Add(new LSL_Integer(AttachmentsPrimsInventoryList.Sum())); + SceneObjectPart[] parts = Attachment.Parts; + int nparts = parts.Count(); + for(int i = 0; i < nparts; i++) + invcount += parts[i].Inventory.Count; + } + } catch { }; + ret.Add(new LSL_Integer(invcount)); break; case ScriptBaseClass.OBJECT_GROUP_TAG: ret.Add(new LSL_String(av.Grouptitle)); @@ -13968,12 +13974,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ret.Add(new LSL_Integer(obj.ParentGroup.PrimCount)); break; case ScriptBaseClass.OBJECT_TOTAL_INVENTORY_COUNT: - LSL_List ObjectPrimsInventoryList = new LSL_List(); - obj.ParentGroup.ForEachPart(delegate(SceneObjectPart part) - { - ObjectPrimsInventoryList.Add(new LSL_Integer(part.Inventory.Count)); - }); - ret.Add(ObjectPrimsInventoryList.Sum()); + SceneObjectPart[] parts = obj.ParentGroup.Parts; + int nparts = parts.Count(); + int count = 0; + for(int i = 0; i < nparts; i++) + count += parts[i].Inventory.Count; + ret.Add(new LSL_Integer(count)); break; case ScriptBaseClass.OBJECT_GROUP_TAG: ret.Add(new LSL_String(String.Empty)); From 7de2c8ae708757f7dc929130d1d097e5589ce36a Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Tue, 29 Nov 2016 03:52:01 +0100 Subject: [PATCH 119/305] The new Constant: integer OBJECT_TEMP_ATTACHED = 34; Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- .../Shared/Api/Implementation/LSL_Api.cs | 13 +++++++++++++ .../Shared/Api/Runtime/LSL_Constants.cs | 1 + 2 files changed, 14 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 80bb461746..9c8d40a8a6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -13792,6 +13792,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_GROUP_TAG: ret.Add(new LSL_String(av.Grouptitle)); break; + case ScriptBaseClass.OBJECT_TEMP_ATTACHED: + ret.Add(new LSL_Integer(0)); + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); @@ -13984,6 +13987,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_GROUP_TAG: ret.Add(new LSL_String(String.Empty)); break; + case ScriptBaseClass.OBJECT_TEMP_ATTACHED: + if (obj.ParentGroup.AttachmentPoint != 0 && obj.ParentGroup.FromItemID == UUID.Zero) + { + ret.Add(new LSL_Integer(1)); + } + else + { + ret.Add(new LSL_Integer(0)); + } + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 17173a2444..48afcc03e1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -641,6 +641,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OBJECT_PRIM_COUNT = 30; public const int OBJECT_TOTAL_INVENTORY_COUNT = 31; public const int OBJECT_GROUP_TAG = 33; + public const int OBJECT_TEMP_ATTACHED = 34; // Pathfinding types public const int OPT_OTHER = -1; From 1863bb29dfa95479aba8fb6251e18cdcf09a7562 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 30 Nov 2016 07:43:17 +0000 Subject: [PATCH 120/305] slow down automatic floatsamAssetCache CleanupExpiredFiles LOT to reduce impact on simulation and to give GC more changes of preventing it from eating up all avaialble physcical memory on loaded machines. --- .../CoreModules/Asset/FlotsamAssetCache.cs | 85 ++++++++++++++++--- 1 file changed, 72 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index c4abc99d3f..025d3cefa1 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -62,6 +62,7 @@ namespace OpenSim.Region.CoreModules.Asset MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled; + private bool m_Running; private const string m_ModuleName = "FlotsamAssetCache"; private const string m_DefaultCacheDirectory = "./assetcache"; @@ -94,7 +95,7 @@ namespace OpenSim.Region.CoreModules.Asset private const double m_DefaultFileExpiration = 48; private TimeSpan m_MemoryExpiration = TimeSpan.FromHours(m_DefaultMemoryExpiration); private TimeSpan m_FileExpiration = TimeSpan.FromHours(m_DefaultFileExpiration); - private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(0.166); + private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(1.0); private static int m_CacheDirectoryTiers = 1; private static int m_CacheDirectoryTierLen = 3; @@ -104,7 +105,8 @@ namespace OpenSim.Region.CoreModules.Asset private IAssetService m_AssetService; private List m_Scenes = new List(); - + private object timerLock = new object(); + public FlotsamAssetCache() { m_InvalidChars.AddRange(Path.GetInvalidPathChars()); @@ -170,14 +172,6 @@ namespace OpenSim.Region.CoreModules.Asset m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory); - if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) - { - m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds); - m_CacheCleanTimer.AutoReset = true; - m_CacheCleanTimer.Elapsed += CleanupExpiredFiles; - lock (m_CacheCleanTimer) - m_CacheCleanTimer.Start(); - } if (m_CacheDirectoryTiers < 1) { @@ -219,7 +213,6 @@ namespace OpenSim.Region.CoreModules.Asset { scene.RegisterModuleInterface(this); m_Scenes.Add(scene); - } } @@ -229,13 +222,39 @@ namespace OpenSim.Region.CoreModules.Asset { scene.UnregisterModuleInterface(this); m_Scenes.Remove(scene); + lock(timerLock) + { + if(m_Scenes.Count <= 0) + { + m_Running = false; + m_CacheCleanTimer.Stop(); + m_CacheCleanTimer.Close(); + } + } } } public void RegionLoaded(Scene scene) { - if (m_Enabled && m_AssetService == null) - m_AssetService = scene.RequestModuleInterface(); + if (m_Enabled) + { + if(m_AssetService == null) + m_AssetService = scene.RequestModuleInterface(); + lock(timerLock) + { + if(!m_Running) + { + if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) + { + m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds); + m_CacheCleanTimer.AutoReset = false; + m_CacheCleanTimer.Elapsed += CleanupExpiredFiles; + m_CacheCleanTimer.Start(); + } + m_Running = true; + } + } + } } //////////////////////////////////////////////////////////// @@ -542,6 +561,8 @@ namespace OpenSim.Region.CoreModules.Asset if (m_LogLevel >= 2) m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration); + if(!m_Running) + return; // Purge all files last accessed prior to this point DateTime purgeLine = DateTime.Now - m_FileExpiration; @@ -554,6 +575,12 @@ namespace OpenSim.Region.CoreModules.Asset { CleanExpiredFiles(dir, purgeLine); } + + lock(timerLock) + { + if(m_Running) + m_CacheCleanTimer.Start(); + } } /// @@ -789,9 +816,15 @@ namespace OpenSim.Region.CoreModules.Asset s.ForEachSOG(delegate(SceneObjectGroup e) { + if(!m_Running && !storeUncached) + return; + gatherer.AddForInspection(e); gatherer.GatherAll(); + if(!m_Running && !storeUncached) + return; + foreach (UUID assetID in gatherer.GatheredUuids.Keys) { if (!assetsFound.ContainsKey(assetID)) @@ -820,7 +853,14 @@ namespace OpenSim.Region.CoreModules.Asset } gatherer.GatheredUuids.Clear(); + if(!m_Running && !storeUncached) + return; + + if(!storeUncached) + Thread.Sleep(50); }); + if(!m_Running && !storeUncached) + break; } return assetsFound.Count; @@ -982,7 +1022,26 @@ namespace OpenSim.Region.CoreModules.Asset WorkManager.RunInThread(delegate { + bool wasRunning= false; + lock(timerLock) + { + if(m_Running) + { + m_CacheCleanTimer.Stop(); + m_Running = false; + wasRunning = true; + Thread.Sleep(100); + } + } int assetReferenceTotal = TouchAllSceneAssets(true); + lock(timerLock) + { + if(wasRunning) + { + m_CacheCleanTimer.Start(); + m_Running = true; + } + } con.OutputFormat("Completed check with {0} assets.", assetReferenceTotal); }, null, "TouchAllSceneAssets"); From e19eb65c18445f5e915b34d3a2cab883405eb661 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 30 Nov 2016 07:52:50 +0000 Subject: [PATCH 121/305] disable floatSam FileCleanupTimer option on ini.example since it is currently a broken resources expensive option. Users should do it by hand when its impact on region is acceptable --- bin/config-include/FlotsamCache.ini.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index ad74fc14e9..0136a81ab3 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -36,7 +36,7 @@ ; How often {in hours} should the disk be checked for expired filed ; Specify 0 to disable expiration checking - FileCleanupTimer = 1.0 ;every hour + FileCleanupTimer = 0 ;every hour ; If WAIT_ON_INPROGRESS_REQUESTS has been defined then this specifies how ; long (in miliseconds) to block a request thread while trying to complete From f2cad38b3de94fa660c2bea5291f2d7f41b04321 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 30 Nov 2016 07:59:01 +0000 Subject: [PATCH 122/305] fix the FileCleanupTimer coment --- bin/config-include/FlotsamCache.ini.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index 0136a81ab3..db8d4db01a 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -36,7 +36,7 @@ ; How often {in hours} should the disk be checked for expired filed ; Specify 0 to disable expiration checking - FileCleanupTimer = 0 ;every hour + FileCleanupTimer = 0.0 ; disabled ; If WAIT_ON_INPROGRESS_REQUESTS has been defined then this specifies how ; long (in miliseconds) to block a request thread while trying to complete From 2020cafc308a99555412324a4de33958593a255a Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 30 Nov 2016 09:22:47 +0000 Subject: [PATCH 123/305] fix null ref on m_CacheCleanTimer control, add a gc.collect on manual floatsam fcache assets comand --- OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 025d3cefa1..9413598de6 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -224,7 +224,7 @@ namespace OpenSim.Region.CoreModules.Asset m_Scenes.Remove(scene); lock(timerLock) { - if(m_Scenes.Count <= 0) + if(m_Running && m_Scenes.Count <= 0) { m_Running = false; m_CacheCleanTimer.Stop(); @@ -250,8 +250,8 @@ namespace OpenSim.Region.CoreModules.Asset m_CacheCleanTimer.AutoReset = false; m_CacheCleanTimer.Elapsed += CleanupExpiredFiles; m_CacheCleanTimer.Start(); + m_Running = true; } - m_Running = true; } } } @@ -834,6 +834,7 @@ namespace OpenSim.Region.CoreModules.Asset if (File.Exists(filename)) { UpdateFileLastAccessTime(filename); + assetsFound[assetID] = true; } else if (storeUncached) { @@ -1034,6 +1035,7 @@ namespace OpenSim.Region.CoreModules.Asset } } int assetReferenceTotal = TouchAllSceneAssets(true); + GC.Collect(); lock(timerLock) { if(wasRunning) From adee1c1bb0b0b452f3774bdabc5dc0b133407b6a Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 30 Nov 2016 10:08:49 +0000 Subject: [PATCH 124/305] fix a null ref --- OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index b1234fec28..d1fe3c7c2f 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs @@ -188,7 +188,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); MapBlockData data; - if (regionInfos.Count > 0) + if (regionInfos != null && regionInfos.Count > 0) { foreach (GridRegion info in regionInfos) { @@ -205,7 +205,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } // final block, closing the search result - AddFinalBlock(blocks,mapNameOrig); + AddFinalBlock(blocks,mapNameOrig); // flags are agent flags sent from the viewer. // they have different values depending on different viewers, apparently From 813ee4e18816de13965d0d67dfbdf15fd661ec41 Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Thu, 1 Dec 2016 03:11:34 +0000 Subject: [PATCH 125/305] Remove unused integer vars from LLClientView --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 6cdf6f635d..68df40f6cd 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -2996,7 +2996,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP return; } - int WearableOut = 0; bool isWearable = false; isWearable = ((AssetType) req.AssetInf.Type == @@ -8563,7 +8562,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // surrounding scene if ((ImageType)block.Type == ImageType.Baked) args.Priority *= 2.0f; - int wearableout = 0; ImageManager.EnqueueReq(args); } From cfb98050f7f51223692ea65510a11423394d9ef5 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 1 Dec 2016 03:43:49 +0000 Subject: [PATCH 126/305] a few changes to cache.cs ( currently not much used ) --- OpenSim/Framework/Cache.cs | 103 ++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 41 deletions(-) diff --git a/OpenSim/Framework/Cache.cs b/OpenSim/Framework/Cache.cs index 31cab4a021..80f5ff44ee 100644 --- a/OpenSim/Framework/Cache.cs +++ b/OpenSim/Framework/Cache.cs @@ -89,14 +89,14 @@ namespace OpenSim.Framework public CacheItemBase(string index) { uuid = index; - entered = DateTime.Now; + entered = DateTime.UtcNow; lastUsed = entered; } public CacheItemBase(string index, DateTime ttl) { uuid = index; - entered = DateTime.Now; + entered = DateTime.UtcNow; lastUsed = entered; expires = ttl; } @@ -215,6 +215,8 @@ namespace OpenSim.Framework private CacheFlags m_Flags = 0; private int m_Size = 1024; private TimeSpan m_DefaultTTL = new TimeSpan(0); + private DateTime m_nextExpire; + private TimeSpan m_expiresTime = new TimeSpan(0,0,30); public ExpireDelegate OnExpire; // Comparison interfaces @@ -233,6 +235,21 @@ namespace OpenSim.Framework return(a.lastUsed.CompareTo(b.lastUsed)); } } + // same as above, reverse order + private class SortLRUrev : IComparer + { + public int Compare(CacheItemBase a, CacheItemBase b) + { + if (a == null && b == null) + return 0; + if (a == null) + return -1; + if (b == null) + return 1; + + return(b.lastUsed.CompareTo(a.lastUsed)); + } + } // Convenience constructors // @@ -241,6 +258,8 @@ namespace OpenSim.Framework m_Strategy = CacheStrategy.Balanced; m_Medium = CacheMedium.Memory; m_Flags = 0; + m_nextExpire = DateTime.UtcNow + m_expiresTime; + m_Strategy = CacheStrategy.Aggressive; } public Cache(CacheMedium medium) : @@ -295,19 +314,23 @@ namespace OpenSim.Framework { lock (m_Index) { - if (Count <= Size) - return; + int target = newSize; + if(m_Strategy == CacheStrategy.Aggressive) + target = (int)(newSize * 0.9); - m_Index.Sort(new SortLRU()); - m_Index.Reverse(); + if(Count > target) + { + m_Index.Sort(new SortLRUrev()); - m_Index.RemoveRange(newSize, Count - newSize); + m_Index.RemoveRange(newSize, Count - target); + + m_Lookup.Clear(); + + foreach (CacheItemBase item in m_Index) + m_Lookup[item.uuid] = item; + } m_Size = newSize; - m_Lookup.Clear(); - - foreach (CacheItemBase item in m_Index) - m_Lookup[item.uuid] = item; } } @@ -335,7 +358,7 @@ namespace OpenSim.Framework } item.hits++; - item.lastUsed = DateTime.Now; + item.lastUsed = DateTime.UtcNow; Expire(true); } @@ -361,30 +384,26 @@ namespace OpenSim.Framework // public virtual Object Get(string index, FetchDelegate fetch) { - Object item = Get(index); + CacheItemBase item = GetItem(index); if (item != null) - return item; + return item.Retrieve(); Object data = fetch(index); - if (data == null) - { - if ((m_Flags & CacheFlags.CacheMissing) != 0) - { - lock (m_Index) - { - CacheItemBase missing = new CacheItemBase(index); - if (!m_Index.Contains(missing)) - { - m_Index.Add(missing); - m_Lookup[index] = missing; - } - } - } + + if (data == null && (m_Flags & CacheFlags.CacheMissing) == 0) return null; + + lock (m_Index) + { + CacheItemBase missing = new CacheItemBase(index); + if (!m_Index.Contains(missing)) + { + m_Index.Add(missing); + m_Lookup[index] = missing; + } } Store(index, data); - return data; } @@ -442,9 +461,9 @@ namespace OpenSim.Framework item = GetItem(index); item.hits++; - item.lastUsed = DateTime.Now; + item.lastUsed = DateTime.UtcNow; if (m_DefaultTTL.Ticks != 0) - item.expires = DateTime.Now + m_DefaultTTL; + item.expires = DateTime.UtcNow + m_DefaultTTL; item.Store(data); } @@ -455,7 +474,7 @@ namespace OpenSim.Framework parameters); if (m_DefaultTTL.Ticks != 0) - item.expires = DateTime.Now + m_DefaultTTL; + item.expires = DateTime.UtcNow + m_DefaultTTL; m_Index.Add(item); m_Lookup[index] = item; @@ -476,10 +495,14 @@ namespace OpenSim.Framework if (getting && (m_Strategy == CacheStrategy.Aggressive)) return; + DateTime now = DateTime.UtcNow; + if(now < m_nextExpire) + return; + + m_nextExpire = now + m_expiresTime; + if (m_DefaultTTL.Ticks != 0) { - DateTime now= DateTime.Now; - foreach (CacheItemBase item in new List(m_Index)) { if (item.expires.Ticks == 0 || @@ -494,16 +517,14 @@ namespace OpenSim.Framework switch (m_Strategy) { case CacheStrategy.Aggressive: - if (Count < Size) - return; - - m_Index.Sort(new SortLRU()); - m_Index.Reverse(); - int target = (int)((float)Size * 0.9); - if (target == Count) // Cover ridiculous cache sizes + if (Count < target) // Cover ridiculous cache sizes return; + target = (int)((float)Size * 0.8); + + m_Index.Sort(new SortLRUrev()); + ExpireDelegate doExpire = OnExpire; if (doExpire != null) From 8299941517d33f533dff7b571cd7a915064b6871 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 1 Dec 2016 03:45:43 +0000 Subject: [PATCH 127/305] fix region overlaps on registration --- OpenSim/Services/GridService/GridService.cs | 112 +++----------------- 1 file changed, 17 insertions(+), 95 deletions(-) diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index 66c918f9e3..a340612320 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -202,10 +202,24 @@ namespace OpenSim.Services.GridService if (regionInfos.RegionID == UUID.Zero) return "Invalid RegionID - cannot be zero UUID"; - String reason = "Region overlaps another region"; - // we should not need to check for overlaps + String reason = "Region overlaps another region"; + + List rdatas = m_Database.Get( + regionInfos.RegionLocX, + regionInfos.RegionLocY, + regionInfos.RegionLocX + regionInfos.RegionSizeX, + regionInfos.RegionLocY + regionInfos.RegionSizeY, + scopeID); + + RegionData region = null; + if(rdatas.Count > 1) + { + m_log.WarnFormat("{0} Register region overlaps with {1} regions", LogHeader, scopeID, rdatas.Count); + return reason; + } + else if(rdatas.Count == 1) + region = rdatas[0]; - RegionData region = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); if ((region != null) && (region.RegionID != regionInfos.RegionID)) { // If not same ID and same coordinates, this new region has conflicts and can't be registered. @@ -341,99 +355,7 @@ namespace OpenSim.Services.GridService return String.Empty; } -/* - /// - /// Search the region map for regions conflicting with this region. - /// The region to be added is passed and we look for any existing regions that are - /// in the requested location, that are large varregions that overlap this region, or - /// are previously defined regions that would lie under this new region. - /// - /// Information on region requested to be added to the world map - /// Grid id for region - /// The reason the returned region conflicts with passed region - /// - private RegionData FindAnyConflictingRegion(GridRegion regionInfos, UUID scopeID, out string reason) - { - reason = "Reregistration"; - // First see if there is an existing region right where this region is trying to go - // (We keep this result so it can be returned if suppressing errors) - RegionData noErrorRegion = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); - RegionData region = noErrorRegion; - if (region != null - && region.RegionID == regionInfos.RegionID - && region.sizeX == regionInfos.RegionSizeX - && region.sizeY == regionInfos.RegionSizeY) - { - // If this seems to be exactly the same region, return this as it could be - // a re-registration (permissions checked by calling routine). - m_log.DebugFormat("{0} FindAnyConflictingRegion: re-register of {1}", - LogHeader, RegionString(regionInfos)); - return region; - } - // No region exactly there or we're resizing an existing region. - // Fetch regions that could be varregions overlapping requested location. - int xmin = regionInfos.RegionLocX - (int)Constants.MaximumRegionSize + 10; - int xmax = regionInfos.RegionLocX; - int ymin = regionInfos.RegionLocY - (int)Constants.MaximumRegionSize + 10; - int ymax = regionInfos.RegionLocY; - List rdatas = m_Database.Get(xmin, ymin, xmax, ymax, scopeID); - foreach (RegionData rdata in rdatas) - { - // m_log.DebugFormat("{0} FindAnyConflictingRegion: find existing. Checking {1}", LogHeader, RegionString(rdata) ); - if ( (rdata.posX + rdata.sizeX > regionInfos.RegionLocX) - && (rdata.posY + rdata.sizeY > regionInfos.RegionLocY) ) - { - region = rdata; - m_log.WarnFormat("{0} FindAnyConflictingRegion: conflict of {1} by existing varregion {2}", - LogHeader, RegionString(regionInfos), RegionString(region)); - reason = String.Format("Region location is overlapped by existing varregion {0}", - RegionString(region)); - - if (m_SuppressVarregionOverlapCheckOnRegistration) - region = noErrorRegion; - return region; - } - } - - // There isn't a region that overlaps this potential region. - // See if this potential region overlaps an existing region. - // First, a shortcut of not looking for overlap if new region is legacy region sized - // and connot overlap anything. - if (regionInfos.RegionSizeX != Constants.RegionSize - || regionInfos.RegionSizeY != Constants.RegionSize) - { - // trim range looked for so we don't pick up neighbor regions just off the edges - xmin = regionInfos.RegionLocX; - xmax = regionInfos.RegionLocX + regionInfos.RegionSizeX - 10; - ymin = regionInfos.RegionLocY; - ymax = regionInfos.RegionLocY + regionInfos.RegionSizeY - 10; - rdatas = m_Database.Get(xmin, ymin, xmax, ymax, scopeID); - - // If the region is being resized, the found region could be ourself. - foreach (RegionData rdata in rdatas) - { - // m_log.DebugFormat("{0} FindAnyConflictingRegion: see if overlap. Checking {1}", LogHeader, RegionString(rdata) ); - if (region == null || region.RegionID != regionInfos.RegionID) - { - region = rdata; - m_log.WarnFormat("{0} FindAnyConflictingRegion: conflict of varregion {1} overlaps existing region {2}", - LogHeader, RegionString(regionInfos), RegionString(region)); - reason = String.Format("Region {0} would overlap existing region {1}", - RegionString(regionInfos), RegionString(region)); - - if (m_SuppressVarregionOverlapCheckOnRegistration) - region = noErrorRegion; - return region; - } - } - } - - // If we get here, region is either null (nothing found here) or - // is the non-conflicting region found at the location being requested. - return region; - } -*/ // String describing name and region location of passed region private String RegionString(RegionData reg) { From 874d663161a146c4a747f4f380ffb3b68ea3bb6a Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 1 Dec 2016 04:02:29 +0000 Subject: [PATCH 128/305] fix region area range --- OpenSim/Services/GridService/GridService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index a340612320..31a186ab3c 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -207,8 +207,8 @@ namespace OpenSim.Services.GridService List rdatas = m_Database.Get( regionInfos.RegionLocX, regionInfos.RegionLocY, - regionInfos.RegionLocX + regionInfos.RegionSizeX, - regionInfos.RegionLocY + regionInfos.RegionSizeY, + regionInfos.RegionLocX + regionInfos.RegionSizeX - 1, + regionInfos.RegionLocY + regionInfos.RegionSizeY - 1 , scopeID); RegionData region = null; From 29f6e3fc7bc3b86400b12958c0661a0c06612b7b Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 1 Dec 2016 04:08:42 +0000 Subject: [PATCH 129/305] fix a typo in dbs region range --- OpenSim/Data/MySQL/MySQLRegionData.cs | 2 +- OpenSim/Data/PGSQL/PGSQLRegionData.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLRegionData.cs b/OpenSim/Data/MySQL/MySQLRegionData.cs index 3dc049b3fa..99d4944b52 100644 --- a/OpenSim/Data/MySQL/MySQLRegionData.cs +++ b/OpenSim/Data/MySQL/MySQLRegionData.cs @@ -204,7 +204,7 @@ namespace OpenSim.Data.MySQL foreach (RegionData r in dbret) { if (r.posX + r.sizeX > startX && r.posX <= endX - && r.posY + r.sizeX > startY && r.posY <= endY) + && r.posY + r.sizeY > startY && r.posY <= endY) ret.Add(r); } return ret; diff --git a/OpenSim/Data/PGSQL/PGSQLRegionData.cs b/OpenSim/Data/PGSQL/PGSQLRegionData.cs index 3924b7bba1..fc352c3905 100644 --- a/OpenSim/Data/PGSQL/PGSQLRegionData.cs +++ b/OpenSim/Data/PGSQL/PGSQLRegionData.cs @@ -211,7 +211,7 @@ namespace OpenSim.Data.PGSQL foreach (RegionData r in dbret) { if (r.posX + r.sizeX > startX && r.posX <= endX - && r.posY + r.sizeX > startY && r.posY <= endY) + && r.posY + r.sizeY > startY && r.posY <= endY) ret.Add(r); } return ret; From 1fdd71f8565ee8a52aa17f9e56ef66ab2889c859 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 1 Dec 2016 07:49:17 +0000 Subject: [PATCH 130/305] do a GC collect on last client exit --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 68df40f6cd..ce7ee98d9b 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -619,11 +619,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityProps = new PriorityQueue(1); m_killRecord.Clear(); GroupsInView.Clear(); -// m_scene = null; can't do this unless checks are added everywhere due to workitems already in pools - //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); - //GC.Collect(); - //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); + if(m_scene.GetNumberOfClients() == 0) + GC.Collect(); } public void Kick(string message) From 6a8b8f3168d251d152fdeac007ab7a3f7a280e39 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 2 Dec 2016 22:56:14 +0000 Subject: [PATCH 131/305] change a wrong error message and avoid a null ref (that may happen due to needed time delays) --- .../EntityTransfer/EntityTransferModule.cs | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 33aa7adfc9..a7105e2bb2 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -2093,19 +2093,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer spScene.SimulationService.UpdateAgent(neighbour, agentpos); } } - catch (ArgumentOutOfRangeException) - { - m_log.ErrorFormat( - "[ENTITY TRANSFER MODULE]: Neighbour Regions response included the current region in the neighbour list. The following region will not display to the client: {0} for region {1} ({2}, {3}).", - neighbour.ExternalHostName, - neighbour.RegionHandle, - neighbour.RegionLocX, - neighbour.RegionLocY); - } catch (Exception e) { m_log.ErrorFormat( - "[ENTITY TRANSFER MODULE]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}", + "[ENTITY TRANSFER MODULE]: Error creating child agent at {0} ({1} ({2}, {3}). {4}", neighbour.ExternalHostName, neighbour.RegionHandle, neighbour.RegionLocX, @@ -2279,24 +2270,28 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// /// - private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData a, GridRegion reg, + private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData agentCircData, GridRegion reg, IPEndPoint endPoint, bool newAgent) { if (newAgent) { + // we may already had lost this sp + if(sp == null || sp.IsDeleted || sp.ClientView == null) // something bad already happened + return; + Scene scene = sp.Scene; m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})", sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY); - string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(a.CapsPath); + string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(agentCircData.CapsPath); string reason = String.Empty; EntityTransferContext ctx = new EntityTransferContext(); - bool regionAccepted = scene.SimulationService.CreateAgent(reg, reg, a, (uint)TeleportFlags.Default, ctx, out reason); + bool regionAccepted = scene.SimulationService.CreateAgent(reg, reg, agentCircData, (uint)TeleportFlags.Default, ctx, out reason); if (regionAccepted) { @@ -2306,6 +2301,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (m_eqModule != null) { #region IP Translation for NAT + if(sp == null || sp.IsDeleted || sp.ClientView == null) // something bad already happened + return; + IClientIPEndpoint ipepClient; if (sp.ClientView.TryGet(out ipepClient)) { From 2ff75e76920a006e4993013540bb50ef61a2f863 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 3 Dec 2016 18:35:31 +0000 Subject: [PATCH 132/305] ubMeshmerizer, fix the orientation of last triangle on top/bottom faces in case on circle hollow shape --- OpenSim/Region/PhysicsModules/ubOdeMeshing/PrimMesher.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/ubOdeMeshing/PrimMesher.cs b/OpenSim/Region/PhysicsModules/ubOdeMeshing/PrimMesher.cs index 2f97caff60..51d067a19c 100644 --- a/OpenSim/Region/PhysicsModules/ubOdeMeshing/PrimMesher.cs +++ b/OpenSim/Region/PhysicsModules/ubOdeMeshing/PrimMesher.cs @@ -718,8 +718,8 @@ namespace PrimMesher } newFace.v1 = 0; - newFace.v2 = numTotalVerts - numHollowVerts; - newFace.v3 = numTotalVerts - 1; + newFace.v2 = numTotalVerts - 1; + newFace.v3 = numTotalVerts - numHollowVerts; faces.Add(newFace); } } From 2a29a270da2cf2c7676437c4b02dad0ed2f4f721 Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Sun, 4 Dec 2016 08:26:29 +0100 Subject: [PATCH 133/305] Adding new string-parameter: "region_max_prims" for llGetEnv(string name); Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- .../Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 9c8d40a8a6..763106fb12 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -6303,6 +6303,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IUrlModule UrlModule = World.RequestModuleInterface(); return UrlModule.ExternalHostNameForLSL; } + else if (name == "region_max_prims") + { + return World.RegionInfo.ObjectCapacity.ToString(); + } else { return ""; From e1cf34d6fb2d43261ad66262af091574c075f489 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 4 Dec 2016 15:50:48 +0000 Subject: [PATCH 134/305] replace GetDisplaynames by a handler really usable as a client cap. Most capabilities.handlers are so it all things not propor PER CLIENT CAP handlers --- .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 84 ++++++++++ .../Linden/Caps/GetDisplayNamesModule.cs | 143 ------------------ 2 files changed, 84 insertions(+), 143 deletions(-) delete mode 100644 OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 60bfaa518b..f96ae8b952 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -29,9 +29,11 @@ using System; using System.Timers; using System.Collections; using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; using System.Reflection; using System.Text; +using System.Web; using OpenMetaverse; using OpenMetaverse.StructuredData; @@ -125,6 +127,8 @@ namespace OpenSim.Region.ClientStack.Linden private bool m_AllowCapHomeLocation = true; private bool m_AllowCapGroupMemberData = true; + private IUserManagement m_UserManager; + private enum FileAgentInventoryState : int { @@ -196,6 +200,7 @@ namespace OpenSim.Region.ClientStack.Linden m_assetService = m_Scene.AssetService; m_regionName = m_Scene.RegionInfo.RegionName; + m_UserManager = m_Scene.RequestModuleInterface(); RegisterHandlers(); @@ -229,6 +234,7 @@ namespace OpenSim.Region.ClientStack.Linden RegisterRegionServiceHandlers(); RegisterInventoryServiceHandlers(); + RegisterOtherHandlers(); } public void RegisterRegionServiceHandlers() @@ -314,6 +320,19 @@ namespace OpenSim.Region.ClientStack.Linden } } + public void RegisterOtherHandlers() + { + try + { + IRequestHandler GetDisplayNamesHandler = new RestStreamHandler( + "GET", GetNewCapPath(), GetDisplayNames, "GetDisplayNames", null); + m_HostCapsObj.RegisterHandler("GetDisplayNames", GetDisplayNamesHandler); + } + catch (Exception e) + { + m_log.Error("[CAPS]: " + e.ToString()); + } + } /// /// Construct a client response detailing all the capabilities this server can provide. /// @@ -1794,6 +1813,71 @@ namespace OpenSim.Region.ClientStack.Linden response = OSDParser.SerializeLLSDXmlString(resp); return response; } + + public string GetDisplayNames(string request, string path, + string param, IOSHttpRequest httpRequest, + IOSHttpResponse httpResponse) + { + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NoContent; + httpResponse.ContentType = "text/plain"; + + ScenePresence sp = m_Scene.GetScenePresence(m_AgentID); + if(sp == null || sp.IsDeleted) + return ""; + + NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); + string[] ids = query.GetValues("ids"); + + if (m_UserManager == null) + { + m_log.Error("[GET_DISPLAY_NAMES]: Cannot fetch display names without a user management component"); + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; + return ""; + } + + Dictionary names = m_UserManager.GetUsersNames(ids); + + OSDMap osdReply = new OSDMap(); + OSDArray agents = new OSDArray(); + + osdReply["agents"] = agents; + foreach (KeyValuePair kvp in names) + { + if (string.IsNullOrEmpty(kvp.Value)) + continue; + if(kvp.Key == UUID.Zero) + continue; + + string[] parts = kvp.Value.Split(new char[] {' '}); + OSDMap osdname = new OSDMap(); + if(parts[0] == "Unknown") + { + osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddHours(1)); + osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddHours(2)); + } + else + { + osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddDays(8)); + osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddMonths(1)); + } + osdname["display_name"] = OSD.FromString(kvp.Value); + osdname["legacy_first_name"] = parts[0]; + osdname["legacy_last_name"] = parts[1]; + osdname["username"] = OSD.FromString(kvp.Value); + osdname["id"] = OSD.FromUUID(kvp.Key); + osdname["is_display_name_default"] = OSD.FromBoolean(true); + + agents.Add(osdname); + } + + // Full content request + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; + //httpResponse.ContentLength = ??; + httpResponse.ContentType = "application/llsd+xml"; + + string reply = OSDParser.SerializeLLSDXmlString(osdReply); + return reply; + } } public class AssetUploader diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs deleted file mode 100644 index bf559d3abe..0000000000 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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; -using System.Collections.Specialized; -using System.Drawing; -using System.Drawing.Imaging; -using System.Reflection; -using System.IO; -using System.Web; -using log4net; -using Nini.Config; -using Mono.Addins; -using OpenMetaverse; -using OpenMetaverse.StructuredData; -using OpenMetaverse.Imaging; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Services.Interfaces; -using Caps = OpenSim.Framework.Capabilities.Caps; -using OpenSim.Capabilities.Handlers; - -namespace OpenSim.Region.ClientStack.Linden -{ - - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetDisplayNamesModule")] - public class GetDisplayNamesModule : INonSharedRegionModule - { - private static readonly ILog m_log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - protected Scene m_scene; - protected IUserManagement m_UserManager; - - protected bool m_Enabled = false; - - protected string m_URL; - - #region ISharedRegionModule Members - - public virtual void Initialise(IConfigSource source) - { - IConfig config = source.Configs["ClientStack.LindenCaps"]; - if (config == null) - return; - - m_URL = config.GetString("Cap_GetDisplayNames", string.Empty); - if (m_URL != string.Empty) - m_Enabled = true; - } - - public virtual void AddRegion(Scene s) - { - if (!m_Enabled) - return; - - m_scene = s; - } - - public virtual void RemoveRegion(Scene s) - { - if (!m_Enabled) - return; - - m_scene.EventManager.OnRegisterCaps -= RegisterCaps; - m_scene = null; - } - - public virtual void RegionLoaded(Scene s) - { - if (!m_Enabled) - return; - - m_UserManager = m_scene.RequestModuleInterface(); - m_scene.EventManager.OnRegisterCaps += RegisterCaps; - } - - public virtual void PostInitialise() - { - } - - public virtual void Close() { } - - public virtual string Name { get { return "GetDisplayNamesModule"; } } - - public virtual Type ReplaceableInterface - { - get { return null; } - } - - #endregion - - public virtual void RegisterCaps(UUID agentID, Caps caps) - { - if (m_URL == "localhost") - { - string capUrl = "/CAPS/" + UUID.Random() + "/"; -// m_log.DebugFormat("[GET_DISPLAY_NAMES]: {0} in region {1}", capUrl, m_scene.RegionInfo.RegionName); - caps.RegisterHandler( - "GetDisplayNames", - new GetDisplayNamesHandler(capUrl, m_UserManager, "GetDisplayNames", agentID.ToString())); - } - else - { -// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); - IExternalCapsModule handler = m_scene.RequestModuleInterface(); - if (handler != null) - handler.RegisterExternalUserCapsHandler(agentID,caps,"GetDisplayNames", m_URL); - else - caps.RegisterHandler("GetDisplayNames", m_URL); - } - } - - } -} From fcd1e36ed6177f3b3e83d7fd829df3a5325c5e9c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 4 Dec 2016 17:01:49 +0000 Subject: [PATCH 135/305] a few changes to new GetDisplaynames and friends --- .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index f96ae8b952..2481d11bd7 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -201,6 +201,8 @@ namespace OpenSim.Region.ClientStack.Linden m_assetService = m_Scene.AssetService; m_regionName = m_Scene.RegionInfo.RegionName; m_UserManager = m_Scene.RequestModuleInterface(); + if (m_UserManager == null) + m_log.Error("[CAPS]: GetDisplayNames disabled because user management component not found"); RegisterHandlers(); @@ -324,9 +326,12 @@ namespace OpenSim.Region.ClientStack.Linden { try { - IRequestHandler GetDisplayNamesHandler = new RestStreamHandler( + if (m_UserManager != null) + { + IRequestHandler GetDisplayNamesHandler = new RestStreamHandler( "GET", GetNewCapPath(), GetDisplayNames, "GetDisplayNames", null); - m_HostCapsObj.RegisterHandler("GetDisplayNames", GetDisplayNamesHandler); + m_HostCapsObj.RegisterHandler("GetDisplayNames", GetDisplayNamesHandler); + } } catch (Exception e) { @@ -1818,22 +1823,23 @@ namespace OpenSim.Region.ClientStack.Linden string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NoContent; + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.Gone; httpResponse.ContentType = "text/plain"; ScenePresence sp = m_Scene.GetScenePresence(m_AgentID); if(sp == null || sp.IsDeleted) return ""; + if(sp.IsInTransit) + { + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.ServiceUnavailable; + httpResponse.AddHeader("Retry-After","30"); + return ""; + } + NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); string[] ids = query.GetValues("ids"); - if (m_UserManager == null) - { - m_log.Error("[GET_DISPLAY_NAMES]: Cannot fetch display names without a user management component"); - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; - return ""; - } Dictionary names = m_UserManager.GetUsersNames(ids); From 7c566dca5a41cd3a9cb0336b00bdf7d63e24d2e9 Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Sun, 4 Dec 2016 07:10:13 +0100 Subject: [PATCH 136/305] The new Constant: integer OBJECT_REZZER_KEY = 32; Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- OpenSim/Data/MySQL/MySQLSimulationData.cs | 9 +++++++-- OpenSim/Data/MySQL/Resources/RegionStore.migrations | 8 ++++++++ OpenSim/Data/SQLite/Resources/RegionStore.migrations | 8 ++++++++ OpenSim/Data/SQLite/SQLiteSimulationData.cs | 3 +++ OpenSim/Framework/TaskInventoryItem.cs | 11 +++++++++++ .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 2 ++ .../Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs | 1 + .../InventoryAccess/InventoryAccessModule.cs | 2 ++ OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 2 ++ OpenSim/Region/Framework/Scenes/SceneGraph.cs | 1 + OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 6 ++++++ OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 10 +++++++++- .../Scenes/Serialization/SceneObjectSerializer.cs | 9 +++++++++ .../ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 6 ++++++ .../ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs | 1 + 15 files changed, 76 insertions(+), 3 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index ab24b765a9..2aaa2ff553 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -167,7 +167,7 @@ namespace OpenSim.Data.MySQL "SitTargetOrientY, SitTargetOrientZ, " + "RegionUUID, CreatorID, " + "OwnerID, GroupID, " + - "LastOwnerID, SceneGroupID, " + + "LastOwnerID, RezzerID, SceneGroupID, " + "PayPrice, PayButton1, " + "PayButton2, PayButton3, " + "PayButton4, LoopedSound, " + @@ -207,7 +207,7 @@ namespace OpenSim.Data.MySQL "?SitTargetOrientW, ?SitTargetOrientX, " + "?SitTargetOrientY, ?SitTargetOrientZ, " + "?RegionUUID, ?CreatorID, ?OwnerID, " + - "?GroupID, ?LastOwnerID, ?SceneGroupID, " + + "?GroupID, ?LastOwnerID, ?RezzerID, ?SceneGroupID, " + "?PayPrice, ?PayButton1, ?PayButton2, " + "?PayButton3, ?PayButton4, ?LoopedSound, " + "?LoopedSoundGain, ?TextureAnimation, " + @@ -1279,6 +1279,10 @@ namespace OpenSim.Data.MySQL prim.OwnerID = DBGuid.FromDB(row["OwnerID"]); prim.GroupID = DBGuid.FromDB(row["GroupID"]); prim.LastOwnerID = DBGuid.FromDB(row["LastOwnerID"]); + if (row["RezzerID"] != DBNull.Value) + prim.RezzerID = DBGuid.FromDB(row["RezzerID"]); + else + prim.RezzerID = UUID.Zero; // explicit conversion of integers is required, which sort // of sucks. No idea if there is a shortcut here or not. @@ -1682,6 +1686,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("OwnerID", prim.OwnerID.ToString()); cmd.Parameters.AddWithValue("GroupID", prim.GroupID.ToString()); cmd.Parameters.AddWithValue("LastOwnerID", prim.LastOwnerID.ToString()); + cmd.Parameters.AddWithValue("RezzerID", prim.RezzerID.ToString()); cmd.Parameters.AddWithValue("OwnerMask", prim.OwnerMask); cmd.Parameters.AddWithValue("NextOwnerMask", prim.NextOwnerMask); cmd.Parameters.AddWithValue("GroupMask", prim.GroupMask); diff --git a/OpenSim/Data/MySQL/Resources/RegionStore.migrations b/OpenSim/Data/MySQL/Resources/RegionStore.migrations index edc04b9a5e..2108c764b3 100644 --- a/OpenSim/Data/MySQL/Resources/RegionStore.migrations +++ b/OpenSim/Data/MySQL/Resources/RegionStore.migrations @@ -453,3 +453,11 @@ MODIFY `cloud_scroll_x` float(9,7) NOT NULL DEFAULT '0.20', MODIFY `cloud_scroll_y` float(9,7) NOT NULL DEFAULT '0.01'; COMMIT; + +:VERSION 56 #----- Add RezzerID field in table prims + +BEGIN; + +ALTER TABLE `prims` ADD COLUMN `RezzerID` char(36) DEFAULT NULL; + +COMMIT; diff --git a/OpenSim/Data/SQLite/Resources/RegionStore.migrations b/OpenSim/Data/SQLite/Resources/RegionStore.migrations index 64624db9b0..eef14d6a46 100644 --- a/OpenSim/Data/SQLite/Resources/RegionStore.migrations +++ b/OpenSim/Data/SQLite/Resources/RegionStore.migrations @@ -363,3 +363,11 @@ CREATE TABLE IF NOT EXISTS bakedterrain( Heightfield blob); COMMIT; + +:VERSION 35 #----- Add RezzerID field in table prims + +BEGIN; + +ALTER TABLE `prims` ADD COLUMN `RezzerID` char(36) DEFAULT NULL; + +COMMIT; diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs index c1c7b7e8f1..5cfc202384 100644 --- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs +++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs @@ -1216,6 +1216,7 @@ namespace OpenSim.Data.SQLite createCol(prims, "OwnerID", typeof(String)); createCol(prims, "GroupID", typeof(String)); createCol(prims, "LastOwnerID", typeof(String)); + createCol(prims, "RezzerID", typeof(String)); createCol(prims, "OwnerMask", typeof(Int32)); createCol(prims, "NextOwnerMask", typeof(Int32)); createCol(prims, "GroupMask", typeof(Int32)); @@ -1679,6 +1680,7 @@ namespace OpenSim.Data.SQLite prim.OwnerID = new UUID((String)row["OwnerID"]); prim.GroupID = new UUID((String)row["GroupID"]); prim.LastOwnerID = new UUID((String)row["LastOwnerID"]); + prim.RezzerID = row["RezzerID"] == DBNull.Value ? UUID.Zero : new UUID((String)row["RezzerID"]); prim.OwnerMask = Convert.ToUInt32(row["OwnerMask"]); prim.NextOwnerMask = Convert.ToUInt32(row["NextOwnerMask"]); prim.GroupMask = Convert.ToUInt32(row["GroupMask"]); @@ -2125,6 +2127,7 @@ namespace OpenSim.Data.SQLite row["OwnerID"] = prim.OwnerID.ToString(); row["GroupID"] = prim.GroupID.ToString(); row["LastOwnerID"] = prim.LastOwnerID.ToString(); + row["RezzerID"] = prim.RezzerID.ToString(); row["OwnerMask"] = prim.OwnerMask; row["NextOwnerMask"] = prim.NextOwnerMask; row["GroupMask"] = prim.GroupMask; diff --git a/OpenSim/Framework/TaskInventoryItem.cs b/OpenSim/Framework/TaskInventoryItem.cs index 2ec4bd1af3..b195bbe237 100644 --- a/OpenSim/Framework/TaskInventoryItem.cs +++ b/OpenSim/Framework/TaskInventoryItem.cs @@ -59,6 +59,7 @@ namespace OpenSim.Framework private int _invType = 0; private UUID _itemID = UUID.Zero; private UUID _lastOwnerID = UUID.Zero; + private UUID _rezzerID = UUID.Zero; private string _name = String.Empty; private uint _nextOwnerMask = FULL_MASK_PERMISSIONS_GENERAL; private UUID _ownerID = UUID.Zero; @@ -254,6 +255,16 @@ namespace OpenSim.Framework } } + public UUID RezzerID + { + get { + return _rezzerID; + } + set { + _rezzerID = value; + } + } + public string Name { get { return _name; diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 2481d11bd7..032104d398 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -1046,6 +1046,7 @@ namespace OpenSim.Region.ClientStack.Linden prim.OwnerID = owner_id; prim.GroupID = UUID.Zero; prim.LastOwnerID = creatorID; + prim.RezzerID = creatorID; prim.CreationDate = Util.UnixTimeSinceEpoch(); if (grp == null) @@ -1093,6 +1094,7 @@ namespace OpenSim.Region.ClientStack.Linden { grp = new SceneObjectGroup(prim); grp.LastOwnerID = creatorID; + grp.RezzerID = creatorID; } else grp.AddPart(prim); diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs index 769fe285ed..713125cffb 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs @@ -284,6 +284,7 @@ namespace OpenSim.Region.ClientStack.Linden prim.OwnerID = AgentId; prim.GroupID = obj.GroupID; prim.LastOwnerID = prim.OwnerID; + prim.RezzerID = AgentId; prim.CreationDate = Util.UnixTimeSinceEpoch(); prim.Name = obj.Name; prim.Description = ""; diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index fa7803f215..771e5fe645 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -981,6 +981,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset. part.LastOwnerID = part.OwnerID; part.OwnerID = remoteClient.AgentId; + part.RezzerID = remoteClient.AgentId; } } @@ -1150,6 +1151,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess part.LastOwnerID = part.OwnerID; part.OwnerID = item.Owner; + part.RezzerID = item.Owner; part.Inventory.ChangeInventoryOwner(item.Owner); } diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 339fc156f3..daf7741999 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -2625,6 +2625,8 @@ namespace OpenSim.Region.Framework.Scenes } group.FromPartID = sourcePart.UUID; + group.RezzerID = group.FromPartID; + if( i == 0) AddNewSceneObject(group, true, curpos, rot, vel); else diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index f5f83caad0..579874afb5 100755 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -1942,6 +1942,7 @@ namespace OpenSim.Region.Framework.Scenes else { part.LastOwnerID = part.ParentGroup.RootPart.LastOwnerID; + part.RezzerID = part.ParentGroup.RootPart.RezzerID; childParts.Add(part); } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 6cdbac5e6d..fcbcc3f9f1 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -886,6 +886,12 @@ namespace OpenSim.Region.Framework.Scenes set { m_rootPart.LastOwnerID = value; } } + public UUID RezzerID + { + get { return m_rootPart.RezzerID; } + set { m_rootPart.RezzerID = value; } + } + public UUID OwnerID { get { return m_rootPart.OwnerID; } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 3a06e7df42..b95b5beb52 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -460,7 +460,7 @@ namespace OpenSim.Region.Framework.Scenes m_name = "Object"; CreationDate = (int)Utils.DateTimeToUnixTime(Rezzed); - LastOwnerID = CreatorID = OwnerID = ownerID; + RezzerID = LastOwnerID = CreatorID = OwnerID = ownerID; UUID = UUID.Random(); Shape = shape; OwnershipCost = 0; @@ -484,6 +484,7 @@ namespace OpenSim.Region.Framework.Scenes #region XML Schema + private UUID _rezzerID; private UUID _lastOwnerID; private UUID _ownerID; private UUID _groupID; @@ -1385,6 +1386,12 @@ namespace OpenSim.Region.Framework.Scenes set { _lastOwnerID = value; } } + public UUID RezzerID + { + get { return _rezzerID; } + set { _rezzerID = value; } + } + public uint BaseMask { get { return _baseMask; } @@ -2222,6 +2229,7 @@ namespace OpenSim.Region.Framework.Scenes // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. dupe.LastOwnerID = OwnerID; + dupe.RezzerID = RezzerID; byte[] extraP = new byte[Shape.ExtraParams.Length]; Array.Copy(Shape.ExtraParams, extraP, extraP.Length); diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 7d3a168f03..0b7379b065 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -428,6 +428,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization m_SOPXmlProcessors.Add("GroupID", ProcessGroupID); m_SOPXmlProcessors.Add("OwnerID", ProcessOwnerID); m_SOPXmlProcessors.Add("LastOwnerID", ProcessLastOwnerID); + m_SOPXmlProcessors.Add("RezzerID", ProcessRezzerID); m_SOPXmlProcessors.Add("BaseMask", ProcessBaseMask); m_SOPXmlProcessors.Add("OwnerMask", ProcessOwnerMask); m_SOPXmlProcessors.Add("GroupMask", ProcessGroupMask); @@ -864,6 +865,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization obj.LastOwnerID = Util.ReadUUID(reader, "LastOwnerID"); } + private static void ProcessRezzerID(SceneObjectPart obj, XmlReader reader) + { + obj.RezzerID = Util.ReadUUID(reader, "RezzerID"); + } + private static void ProcessBaseMask(SceneObjectPart obj, XmlReader reader) { obj.BaseMask = (uint)reader.ReadElementContentAsInt("BaseMask", String.Empty); @@ -1452,6 +1458,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization UUID lastOwnerID = options.ContainsKey("wipe-owners") ? UUID.Zero : sop.LastOwnerID; WriteUUID(writer, "LastOwnerID", lastOwnerID, options); + UUID rezzerID = options.ContainsKey("wipe-owners") ? UUID.Zero : sop.RezzerID; + WriteUUID(writer, "RezzerID", rezzerID, options); + writer.WriteElementString("BaseMask", sop.BaseMask.ToString()); writer.WriteElementString("OwnerMask", sop.OwnerMask.ToString()); writer.WriteElementString("GroupMask", sop.GroupMask.ToString()); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 763106fb12..71e8ca9593 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -13793,6 +13793,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } catch { }; ret.Add(new LSL_Integer(invcount)); break; + case ScriptBaseClass.OBJECT_REZZER_KEY: + ret.Add(new LSL_Key(id)); + break; case ScriptBaseClass.OBJECT_GROUP_TAG: ret.Add(new LSL_String(av.Grouptitle)); break; @@ -13988,6 +13991,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api count += parts[i].Inventory.Count; ret.Add(new LSL_Integer(count)); break; + case ScriptBaseClass.OBJECT_REZZER_KEY: + ret.Add(new LSL_Key(obj.ParentGroup.RezzerID.ToString())); + break; case ScriptBaseClass.OBJECT_GROUP_TAG: ret.Add(new LSL_String(String.Empty)); break; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 48afcc03e1..734d878c86 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -640,6 +640,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OBJECT_OMEGA = 29; public const int OBJECT_PRIM_COUNT = 30; public const int OBJECT_TOTAL_INVENTORY_COUNT = 31; + public const int OBJECT_REZZER_KEY = 32; public const int OBJECT_GROUP_TAG = 33; public const int OBJECT_TEMP_ATTACHED = 34; From 51104be6d41170bc17d0d24278868b6c1cddfed7 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 4 Dec 2016 17:56:47 +0000 Subject: [PATCH 137/305] remove SOG.FromPartID from main code and flag it obsolete --- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 3 +-- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 7 ++++++- .../Scripting/JsonStore/JsonStoreScriptModule.cs | 2 +- .../ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 6 ++++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index daf7741999..61ea8acd0f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -2624,8 +2624,7 @@ namespace OpenSim.Region.Framework.Scenes group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint; } - group.FromPartID = sourcePart.UUID; - group.RezzerID = group.FromPartID; + group.RezzerID = sourcePart.UUID; if( i == 0) AddNewSceneObject(group, true, curpos, rot, vel); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index fcbcc3f9f1..e42b6757f0 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1059,7 +1059,12 @@ namespace OpenSim.Region.Framework.Scenes /// /// If not applicable will be UUID.Zero /// - public UUID FromPartID { get; set; } + /// obsolete use RezzerID + public UUID FromPartID + { + get { return RezzerID; } + set {RezzerID = value; } + } /// /// The folder ID that this object was rezzed from, if applicable. diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs index e7d461fba6..7a0370a681 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs @@ -783,7 +783,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint; } - group.FromPartID = host.RootPart.UUID; + group.RezzerID = host.RootPart.UUID; m_scene.AddNewSceneObject(group, true, curpos, rot, vel); UUID storeID = group.UUID; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index a21a0caa4e..19f2d0972b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -4030,8 +4030,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { CheckThreatLevel(ThreatLevel.None, "osGetRezzingObject"); m_host.AddScriptLPS(1); - - return new LSL_Key(m_host.ParentGroup.FromPartID.ToString()); + UUID rezID = m_host.ParentGroup.RezzerID; + if(rezID == UUID.Zero || m_host.ParentGroup.Scene.GetScenePresence(rezID) != null) + return new LSL_Key(UUID.Zero.ToString()); + return new LSL_Key(rezID.ToString()); } /// From 181b1ad82b0ec5ca6e1ef107020a81e961f4da56 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 4 Dec 2016 23:02:40 +0000 Subject: [PATCH 138/305] HG: fix the never ending avatar confirmation when 2 users from same grid made friendship on another grid --- .../Avatar/Friends/HGFriendsModule.cs | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index 27b737632c..995474910e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -337,7 +337,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (UUID.TryParse(friendID, out id)) return base.FriendshipMessage(friendID); - return "Please confirm this friendship you made while you were away."; + return "Please confirm this friendship you made while you where on another HG grid"; } protected override FriendInfo GetFriend(FriendInfo[] friends, UUID friendID) @@ -456,6 +456,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { // local grid users m_log.DebugFormat("[HGFRIENDS MODULE]: Users are both local"); + DeletePreviousHGRelations(agentID, friendID); base.StoreFriendships(agentID, friendID); return; } @@ -624,6 +625,45 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } } + private void DeletePreviousHGRelations(UUID a1, UUID a2) + { + // Delete any previous friendship relations + FriendInfo[] finfos = null; + finfos = GetFriendsFromCache(a1); + if (finfos != null) + { + foreach (FriendInfo f in finfos) + { + if (f.TheirFlags == -1) + { + if (f.Friend.StartsWith(a2.ToString())) + { + FriendsService.Delete(a1, f.Friend); + // and also the converse + FriendsService.Delete(f.Friend, a1.ToString()); + } + } + } + } + + finfos = GetFriendsFromCache(a1); + if (finfos != null) + { + foreach (FriendInfo f in finfos) + { + if (f.TheirFlags == -1) + { + if (f.Friend.StartsWith(a1.ToString())) + { + FriendsService.Delete(a2, f.Friend); + // and also the converse + FriendsService.Delete(f.Friend, a2.ToString()); + } + } + } + } + } + protected override bool DeleteFriendship(UUID agentID, UUID exfriendID) { Boolean agentIsLocal = true; From 8db69d2e02b13edb348a13a33c82eda3f7124636 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 6 Dec 2016 07:26:26 +0000 Subject: [PATCH 139/305] remove redundante check for ssl listener --- OpenSim/Capabilities/Caps.cs | 2 +- OpenSim/Capabilities/CapsHandlers.cs | 28 ++++++---------------------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs index 5e89c388f4..7ba65c9a76 100644 --- a/OpenSim/Capabilities/Caps.cs +++ b/OpenSim/Capabilities/Caps.cs @@ -136,7 +136,7 @@ namespace OpenSim.Framework.Capabilities } m_agentID = agent; - m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort, (httpServer == null) ? false : httpServer.UseSSL); + m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort); m_regionName = regionName; m_capsActive.Reset(); } diff --git a/OpenSim/Capabilities/CapsHandlers.cs b/OpenSim/Capabilities/CapsHandlers.cs index 04cede1144..6ec375b268 100644 --- a/OpenSim/Capabilities/CapsHandlers.cs +++ b/OpenSim/Capabilities/CapsHandlers.cs @@ -53,31 +53,15 @@ namespace OpenSim.Framework.Capabilities /// base HTTP server /// host name of the HTTP server /// HTTP port - public CapsHandlers(BaseHttpServer httpListener, string httpListenerHostname, uint httpListenerPort) - : this(httpListener,httpListenerHostname,httpListenerPort, false) - { - } - - /// - /// CapsHandlers is a cap handler container but also takes - /// care of adding and removing cap handlers to and from the - /// supplied BaseHttpServer. - /// - /// base HTTP server - /// host name of the HTTP - /// server - /// HTTP port - public CapsHandlers(IHttpServer httpListener, string httpListenerHostname, uint httpListenerPort, bool https) - { + public CapsHandlers(IHttpServer httpListener, string httpListenerHostname, uint httpListenerPort) + { m_httpListener = httpListener; m_httpListenerHostName = httpListenerHostname; m_httpListenerPort = httpListenerPort; - m_useSSL = https; - if (httpListener != null && m_useSSL) - { - m_httpListenerHostName = httpListener.SSLCommonName; - m_httpListenerPort = httpListener.SSLPort; - } + if (httpListener.UseSSL) + m_useSSL = true; + else + m_useSSL = false; } /// From 44588ce45ef1d23ca8fedd453e9d2e54f1af27a3 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 6 Dec 2016 07:40:45 +0000 Subject: [PATCH 140/305] jenkins likes null httplisteners --- OpenSim/Capabilities/CapsHandlers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Capabilities/CapsHandlers.cs b/OpenSim/Capabilities/CapsHandlers.cs index 6ec375b268..6d3b9b54bf 100644 --- a/OpenSim/Capabilities/CapsHandlers.cs +++ b/OpenSim/Capabilities/CapsHandlers.cs @@ -58,7 +58,7 @@ namespace OpenSim.Framework.Capabilities m_httpListener = httpListener; m_httpListenerHostName = httpListenerHostname; m_httpListenerPort = httpListenerPort; - if (httpListener.UseSSL) + if (httpListener != null && httpListener.UseSSL) m_useSSL = true; else m_useSSL = false; From 240ab951b52aa87434cc02736a4ef84d95470082 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 6 Dec 2016 16:15:57 +0000 Subject: [PATCH 141/305] let NPCs have profile --- .../Avatar/UserProfiles/UserProfileModule.cs | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 61835f9d71..47914cc313 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -320,13 +320,12 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles UUID targetID; UUID.TryParse(args[0], out targetID); - // Can't handle NPC yet... - ScenePresence p = FindPresence(targetID); - if (null != p) + ScenePresence p = FindPresence(targetID); + if (p != null && p.isNPC) { - if (p.PresenceType == PresenceType.Npc) - return; + remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), new Dictionary()); + return; } string serverURI = string.Empty; @@ -575,10 +574,10 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles // Can't handle NPC yet... ScenePresence p = FindPresence(targetId); - if (null != p) + if (p != null && p.isNPC) { - if (p.PresenceType == PresenceType.Npc) - return; + remoteClient.SendAvatarPicksReply(new UUID(args[0]), new Dictionary()); + return; } string serverURI = string.Empty; @@ -860,6 +859,14 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// public void NotesUpdate(IClientAPI remoteClient, UUID queryTargetID, string queryNotes) { + ScenePresence p = FindPresence(queryTargetID); + if (p != null && p.isNPC) + { + remoteClient.SendAgentAlertMessage( + "Notes for NPCs not avaiable", false); + return; + } + UserProfileNotes note = new UserProfileNotes(); note.UserId = remoteClient.AgentId; @@ -1000,10 +1007,14 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles // Can't handle NPC yet... ScenePresence p = FindPresence(avatarID); - if (null != p) + if (p != null && p.isNPC) { - if (p.PresenceType == PresenceType.Npc) - return; + remoteClient.SendAvatarProperties(avatarID, "im a happy NPC", "5/25/1977" , + Utils.StringToBytes("NPC"), "NPCs have no life", 0, + UUID.Zero, UUID.Zero, "", UUID.Zero); + remoteClient.SendAvatarInterestsReply(avatarID, 0, "", + 0, "Getting into trouble", "Droidspeak"); + return; } string serverURI = string.Empty; From d4e285b1a1da036220d9b3a7141ebe1b865c5d35 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 6 Dec 2016 17:05:02 +0000 Subject: [PATCH 142/305] add osNpcSetProfileAbout(LSL_Key npc, string about) to set NPCs profile About text. requires OsNpcCreate rights --- .../Avatar/UserProfiles/UserProfileModule.cs | 4 ++-- .../Region/Framework/Interfaces/INPCModule.cs | 1 + .../OptionalModules/World/NPC/NPCAvatar.cs | 13 ++++++++++++- .../Shared/Api/Implementation/OSSL_Api.cs | 19 +++++++++++++++++++ .../Shared/Api/Interface/IOSSL_Api.cs | 1 + .../Shared/Api/Runtime/OSSL_Stub.cs | 5 +++++ 6 files changed, 40 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 47914cc313..94dc5f5e23 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -863,7 +863,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (p != null && p.isNPC) { remoteClient.SendAgentAlertMessage( - "Notes for NPCs not avaiable", false); + "Notes for NPCs not available", false); return; } @@ -1009,7 +1009,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (p != null && p.isNPC) { - remoteClient.SendAvatarProperties(avatarID, "im a happy NPC", "5/25/1977" , + remoteClient.SendAvatarProperties(avatarID, ((INPC)(p.ControllingClient)).profileAbout, "5/25/1977", Utils.StringToBytes("NPC"), "NPCs have no life", 0, UUID.Zero, UUID.Zero, "", UUID.Zero); remoteClient.SendAvatarInterestsReply(avatarID, 0, "", diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs index 58ea309f99..13103584e1 100644 --- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs +++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs @@ -58,6 +58,7 @@ namespace OpenSim.Region.Framework.Interfaces bool SenseAsAgent { get; } UUID ActiveGroupId { get; set; } UUID Owner { get; } + string profileAbout { get; set; } } public interface INPCModule diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 1ad71ba4cc..1096eae7b7 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -69,7 +69,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC private readonly Scene m_scene; private readonly UUID m_ownerID; private UUID m_hostGroupID; - + private string m_profileAbout = ""; public List SelectedObjects {get; private set;} public NPCAvatar( @@ -98,6 +98,17 @@ namespace OpenSim.Region.OptionalModules.World.NPC m_hostGroupID = UUID.Zero; } + public string profileAbout + { + get { return m_profileAbout; } + set + { + if(value.Length > 255) + m_profileAbout = value.Substring(0,255); + else + m_profileAbout = value; + } + } public IScene Scene { get { return m_scene; } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 19f2d0972b..b101cf9b44 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -2999,6 +2999,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + public void osNpcSetProfileAbout(LSL_Key npc, string about) + { + CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); + m_host.AddScriptLPS(1); + + INPCModule module = World.RequestModuleInterface(); + if (module != null) + { + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + ScenePresence sp = World.GetScenePresence(npcId); + if (sp != null) + ((INPC)(sp.ControllingClient)).profileAbout = about; + } + } + public void osNpcSay(LSL_Key npc, string message) { osNpcSay(npc, 0, message); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 5ce859ee36..87b09675b2 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -343,6 +343,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces rotation osNpcGetRot(key npc); void osNpcSetRot(LSL_Key npc, rotation rot); void osNpcStopMoveToTarget(LSL_Key npc); + void osNpcSetProfileAbout(LSL_Key npc, string about); void osNpcSay(key npc, string message); void osNpcSay(key npc, int channel, string message); void osNpcShout(key npc, int channel, string message); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index c5cb88e05f..5bc998e8c1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -637,6 +637,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_OSSL_Functions.osNpcStopMoveToTarget(npc); } + public void osNpcSetProfileAbout(LSL_Key npc, string about) + { + m_OSSL_Functions.osNpcSetProfileAbout(npc, about); + } + public void osNpcSay(key npc, string message) { m_OSSL_Functions.osNpcSay(npc, message); From de36092d23736f448f5612cbe8b1965422e13a6c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 6 Dec 2016 17:16:47 +0000 Subject: [PATCH 143/305] if we have profile then npc is online --- .../Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 94dc5f5e23..5be8556eb8 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -1010,7 +1010,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (p != null && p.isNPC) { remoteClient.SendAvatarProperties(avatarID, ((INPC)(p.ControllingClient)).profileAbout, "5/25/1977", - Utils.StringToBytes("NPC"), "NPCs have no life", 0, + Utils.StringToBytes("Non Player Character (NPC)"), "NPCs have no life", 16, UUID.Zero, UUID.Zero, "", UUID.Zero); remoteClient.SendAvatarInterestsReply(avatarID, 0, "", 0, "Getting into trouble", "Droidspeak"); From f1c6769ca5a2e49fcfa4aa17c27173af6b49df2f Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 7 Dec 2016 02:14:26 +0000 Subject: [PATCH 144/305] set HasGridUserTried on usercache of NPCs --- .../Framework/UserManagement/UserManagementModule.cs | 4 ++-- OpenSim/Region/Framework/Scenes/Scene.cs | 2 +- OpenSim/Services/Interfaces/IUserManagement.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 5507526310..2701912d18 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -805,7 +805,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return !userdata.IsUnknownUser; } - public virtual void AddUser(UUID uuid, string first, string last) + public virtual void AddUser(UUID uuid, string first, string last, bool isNPC = false) { lock(m_UserCache) { @@ -816,7 +816,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement user.FirstName = first; user.LastName = last; user.IsUnknownUser = false; - user.HasGridUserTried = false; + user.HasGridUserTried = isNPC; m_UserCache.Add(uuid, user); } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 09f0b19201..e44f11a54e 100755 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3226,7 +3226,7 @@ namespace OpenSim.Region.Framework.Scenes if (sp != null && sp.PresenceType == PresenceType.Npc) { - UserManagementModule.AddUser(aCircuit.AgentID, first, last); + UserManagementModule.AddUser(aCircuit.AgentID, first, last, true); } else { diff --git a/OpenSim/Services/Interfaces/IUserManagement.cs b/OpenSim/Services/Interfaces/IUserManagement.cs index 225560e00b..91b344e0dc 100644 --- a/OpenSim/Services/Interfaces/IUserManagement.cs +++ b/OpenSim/Services/Interfaces/IUserManagement.cs @@ -79,7 +79,7 @@ namespace OpenSim.Services.Interfaces /// /// /// - void AddUser(UUID uuid, string firstName, string lastName); + void AddUser(UUID uuid, string first, string last, bool isNPC = false); /// /// Add a user. From 9042aa89683e690c42d27482964368edae9a6b84 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 7 Dec 2016 04:56:35 +0000 Subject: [PATCH 145/305] add missing sp Intransit control --- .../EntityTransfer/EntityTransferModule.cs | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index a7105e2bb2..ad094b4b91 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -776,6 +776,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer else if (sp.Flying) teleportFlags |= (uint)TeleportFlags.IsFlying; + sp.IsInTransit = true; + if (DisableInterRegionTeleportCancellation) teleportFlags |= (uint)TeleportFlags.DisableCancel; @@ -878,7 +880,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); sp.ControllingClient.SendTeleportFailed(reason); - + sp.IsInTransit = false; return; } @@ -889,7 +891,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) @@ -899,7 +901,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -960,7 +962,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -977,7 +979,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -986,6 +988,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, finalDestination.RegionName, sp.Scene.Name); Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); + sp.IsInTransit = false; return; } @@ -998,7 +1001,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, finalDestination.RegionName, sp.Scene.Name); CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination); - + sp.IsInTransit = false; return; } @@ -1035,7 +1038,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -1044,7 +1047,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); - + sp.IsInTransit = false; return; } @@ -1093,6 +1096,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Thread.Sleep(500); sp.Scene.CloseAgent(sp.UUID, false); } + sp.IsInTransit = false; } private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, @@ -1115,7 +1119,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); sp.ControllingClient.SendTeleportFailed(reason); - + sp.IsInTransit = false; return; } @@ -1127,6 +1131,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); + sp.IsInTransit = false; return; } else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) @@ -1137,6 +1142,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); + sp.IsInTransit = false; return; } @@ -1189,7 +1195,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -1198,6 +1204,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, finalDestination.RegionName, sp.Scene.Name); Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); + sp.IsInTransit = false; return; } @@ -1255,6 +1262,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Reset(); } */ + sp.IsInTransit = false; } /// From 4639409dbe0a05136f61fba773b84666c99b2264 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 7 Dec 2016 21:30:36 +0000 Subject: [PATCH 146/305] change caps Sethome fail error report --- .../Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 032104d398..6873325893 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -1675,7 +1675,7 @@ namespace OpenSim.Region.ClientStack.Linden if(fail) { if(client != null) - client.SendAlertMessage(message, "HomePositionSet"); + client.SendAlertMessage(message); response = OSDParser.SerializeLLSDXmlString(resp); return response; } From 18ff3eb2271ed2f58da35a83835b5d679a9ce33b Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 8 Dec 2016 23:56:14 +0000 Subject: [PATCH 147/305] JsonRpc: don't try to connect to a empty uri --- OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs index 2fe1a7d8bc..f3faf4f6d4 100644 --- a/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs @@ -77,6 +77,9 @@ namespace OpenSim.Framework.Servers.HttpServer if (parameters == null) throw new ArgumentNullException("parameters"); + if(string.IsNullOrWhiteSpace(uri)) + return false; + OSDMap request = new OSDMap(); request.Add("jsonrpc", OSD.FromString("2.0")); request.Add("id", OSD.FromString(jsonId)); From 82fb737b8d655187b25267efc8b2da368cfe1e9f Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 9 Dec 2016 08:20:35 +0000 Subject: [PATCH 148/305] HG: add missing information on GetRegion --- OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs index 2d0b2b68f5..6bd24dbc1b 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs @@ -125,6 +125,7 @@ namespace OpenSim.Server.Handlers.Hypergrid hash["hostname"] = regInfo.ExternalHostName; hash["http_port"] = regInfo.HttpPort.ToString(); hash["internal_port"] = regInfo.InternalEndPoint.Port.ToString(); + hash["server_uri"] = regInfo.ServerURI; } if (message != null) From 575825193b51d13c6576aabe1bbaf1f3dda1fad8 Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Fri, 9 Dec 2016 20:46:27 +0100 Subject: [PATCH 149/305] The new string-parameter: "region_object_bonus" for llGetEnv(string name); Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- .../Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 71e8ca9593..7efdc62d43 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -6307,6 +6307,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { return World.RegionInfo.ObjectCapacity.ToString(); } + else if (name == "region_object_bonus") + { + return World.RegionInfo.RegionSettings.ObjectBonus.ToString(); + } else { return ""; From 66990394c9a60e596cc07c4b547291afd7447133 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 9 Dec 2016 22:56:11 +0000 Subject: [PATCH 150/305] avoid a null ref --- OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index d1fe3c7c2f..fb63c6a95f 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs @@ -216,7 +216,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap // while we don't fix the hard-coded urls if (flags == 2) { - if (regionInfos.Count == 0) + if (regionInfos == null || regionInfos.Count == 0) remoteClient.SendAgentAlertMessage("No regions found with that name.", true); // else if (regionInfos.Count == 1) // remoteClient.SendAgentAlertMessage("Region found!", false); From a3e2a42f0d7b1e146892de3d5ddb7b5a96df0d4d Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 10 Dec 2016 01:00:48 +0000 Subject: [PATCH 151/305] HG regions URI need to include also the default ports for compatibility --- OpenSim/Services/GridService/HypergridLinker.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs index e00025bfef..ceb2c6e7bb 100644 --- a/OpenSim/Services/GridService/HypergridLinker.cs +++ b/OpenSim/Services/GridService/HypergridLinker.cs @@ -255,11 +255,8 @@ namespace OpenSim.Services.GridService regionName = parts[2]; } - if(port == 80) - serverURI = "http://"+ host + "/"; - else - serverURI = "http://"+ host +":"+ port.ToString() + "/"; - } + serverURI = "http://"+ host +":"+ port.ToString() + "/"; + } } else { @@ -301,6 +298,10 @@ namespace OpenSim.Services.GridService if(!string.IsNullOrEmpty(regionName)) regionName = regionName.Trim(new char[] { '"', ' ' }); serverURI = uri.AbsoluteUri; + if(uri.Port == 80) + serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":80/"; + else if(uri.Port == 443) + serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":443/"; return true; } From f57403909f36fe6cc46d2ee4cc8c9cd59e6aacf3 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 10 Dec 2016 02:03:00 +0000 Subject: [PATCH 152/305] do not try xbakes on HG --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 2cf0e9d3ac..d501b7f32e 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2125,11 +2125,12 @@ namespace OpenSim.Region.Framework.Scenes if (!gotCrossUpdate && !isNPC) Scene.SendLayerData(ControllingClient); - // HG delay - if((m_teleportFlags & TeleportFlags.ViaHGLogin) != 0) + // HG + bool isHGTP = (m_teleportFlags & TeleportFlags.ViaHGLogin) != 0; + if(isHGTP) { - Thread.Sleep(500); - m_log.DebugFormat("[CompleteMovement] HG delay: {0}ms", Util.EnvironmentTickCountSubtract(ts)); +// ControllingClient.SendNameReply(m_uuid, Firstname, Lastname); + m_log.DebugFormat("[CompleteMovement] HG"); } m_previusParcelHide = false; @@ -2151,7 +2152,7 @@ namespace OpenSim.Region.Framework.Scenes cachedbaked = true; else { - if (m_scene.AvatarFactory != null) + if (m_scene.AvatarFactory != null && !isHGTP) cachedbaked = m_scene.AvatarFactory.ValidateBakedTextureCache(this); // not sure we need this From d49a5374c37967110a8bf11844893f62951878ee Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Sat, 10 Dec 2016 18:03:05 +0000 Subject: [PATCH 153/305] Make it more unlikely that a script teleport will be caught by default region landing point. --- .../Framework/EntityTransfer/EntityTransferModule.cs | 2 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index ad094b4b91..58d6cf2675 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -456,7 +456,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } // Check Default Location (Also See ScenePresence.CompleteMovement) - if (position.X == 128f && position.Y == 128f) + if (position.X == 128f && position.Y == 128f && position.Z == 22.5f) position = sp.Scene.RegionInfo.DefaultLandingPoint; // TODO: Get proper AVG Height diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index d501b7f32e..463f6c8d0d 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2044,7 +2044,7 @@ namespace OpenSim.Region.Framework.Scenes } // Check Default Location (Also See EntityTransferModule.TeleportAgentWithinRegion) - if (AbsolutePosition.X == 128f && AbsolutePosition.Y == 128f) + if (AbsolutePosition.X == 128f && AbsolutePosition.Y == 128f && AbsolutePosition.Z == 22.5f) AbsolutePosition = Scene.RegionInfo.DefaultLandingPoint; if (!MakeRootAgent(AbsolutePosition, flying, ref look)) From 5ad8bceb1da94244c7f3b569e0b342b9c386a4aa Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sat, 10 Dec 2016 18:36:10 +0000 Subject: [PATCH 154/305] Fix OpenSim bombing when a MySQL connection string doesn't contain a password. Passwordless connection is perfectly legal and makes sense within a container. --- OpenSim/Framework/Util.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 01a06cd15c..a6fd99f30f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1685,6 +1685,8 @@ namespace OpenSim.Framework // hide the password in the connection string passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase); + if (passPosition == -1) + return connectionString; passPosition = connectionString.IndexOf("=", passPosition); if (passPosition < connectionString.Length) passPosition += 1; From 5b7986e6beb3d452a2845fa367b26c818098aba5 Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Sat, 10 Dec 2016 21:15:22 +0100 Subject: [PATCH 155/305] Setting precise date of creation in NPC's profile. Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- .../CoreModules/Avatar/UserProfiles/UserProfileModule.cs | 2 +- OpenSim/Region/Framework/Interfaces/INPCModule.cs | 1 + OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs | 7 +++++++ OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs | 2 ++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 5be8556eb8..7d68299cd5 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -1009,7 +1009,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (p != null && p.isNPC) { - remoteClient.SendAvatarProperties(avatarID, ((INPC)(p.ControllingClient)).profileAbout, "5/25/1977", + remoteClient.SendAvatarProperties(avatarID, ((INPC)(p.ControllingClient)).profileAbout, ((INPC)(p.ControllingClient)).Born, Utils.StringToBytes("Non Player Character (NPC)"), "NPCs have no life", 16, UUID.Zero, UUID.Zero, "", UUID.Zero); remoteClient.SendAvatarInterestsReply(avatarID, 0, "", diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs index 13103584e1..dd4226cde7 100644 --- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs +++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs @@ -59,6 +59,7 @@ namespace OpenSim.Region.Framework.Interfaces UUID ActiveGroupId { get; set; } UUID Owner { get; } string profileAbout { get; set; } + string Born { get; set; } } public interface INPCModule diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 1096eae7b7..b904353611 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -70,6 +70,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC private readonly UUID m_ownerID; private UUID m_hostGroupID; private string m_profileAbout = ""; + private string m_born; public List SelectedObjects {get; private set;} public NPCAvatar( @@ -611,6 +612,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC set { } } + public string Born + { + get { return m_born; } + set { m_born = value; } + } + public bool IsGroupMember(UUID groupID) { return (m_hostGroupID == groupID); diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 8462661232..ced82e6b57 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -168,6 +168,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC AvatarAppearance appearance) { NPCAvatar npcAvatar = null; + string born = DateTime.UtcNow.ToString(); try { @@ -222,6 +223,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC ScenePresence sp; if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp)) { + npcAvatar.Born = born; npcAvatar.ActiveGroupId = groupID; sp.CompleteMovement(npcAvatar, false); sp.Grouptitle = groupTitle; From ba61b64c424abed18052a68955f996d9eb81d9b7 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sun, 11 Dec 2016 20:50:17 +0000 Subject: [PATCH 156/305] If a region address is resolveable to a single address, resolve it on startup and use that address This change facilitates running opensim within containers and VMs where the external address isn't that of the VM/container but that of the host. --- OpenSim/Framework/RegionInfo.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index ca17793e64..f764a347f6 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -708,7 +708,11 @@ namespace OpenSim.Framework } else { - m_externalHostName = externalName; + IPAddress[] addrs = Dns.GetHostAddresses(externalName); + if (addrs.Length != 1) // If it is ambiguous or not resolveable, use it literally + m_externalHostName = externalName; + else + m_externalHostName = addrs[0].ToString(); } // RegionType From 4d1536f1ecde8ed03e1f2e69f45207eb9dddfa7c Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Mon, 12 Dec 2016 00:07:36 +0000 Subject: [PATCH 157/305] Allow OpenSim to respond to Unix signals. This may need work to be properly ignoed on Windows. Windows devs, please test and check for platform flags if this causes issues in Windows --- OpenSim/Region/Application/OpenSim.cs | 25 +++++++++++++++++++++++-- bin/Mono.Posix.dll | Bin 0 -> 207872 bytes prebuild.xml | 1 + 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100755 bin/Mono.Posix.dll diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index cf2bf33231..203fe5ec8b 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -26,6 +26,7 @@ */ using System; +using System.Threading; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -74,7 +75,7 @@ namespace OpenSim private string m_timedScript = "disabled"; private int m_timeInterval = 1200; - private Timer m_scriptTimer; + private System.Timers.Timer m_scriptTimer; public OpenSim(IConfigSource configSource) : base(configSource) { @@ -125,6 +126,25 @@ namespace OpenSim m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod); } + private static Mono.Unix.UnixSignal[] signals = new Mono.Unix.UnixSignal[] + { +// new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGINT), + new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGTERM) + }; + + private Thread signal_thread = new Thread (delegate () + { + System.Console.WriteLine("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"); + while (true) + { + // Wait for a signal to be delivered + int index = Mono.Unix.UnixSignal.WaitAny (signals, -1); + + //Mono.Unix.Native.Signum signal = signals [index].Signum; + MainConsole.Instance.RunCommand("shutdown"); + } + }); + /// /// Performs initialisation of the scene, such as loading configuration from disk. /// @@ -134,6 +154,7 @@ namespace OpenSim m_log.Info("========================= STARTING OPENSIM ========================="); m_log.Info("===================================================================="); + signal_thread.Start(); //m_log.InfoFormat("[OPENSIM MAIN]: GC Is Server GC: {0}", GCSettings.IsServerGC.ToString()); // http://msdn.microsoft.com/en-us/library/bb384202.aspx //GCSettings.LatencyMode = GCLatencyMode.Batch; @@ -217,7 +238,7 @@ namespace OpenSim // Start timer script (run a script every xx seconds) if (m_timedScript != "disabled") { - m_scriptTimer = new Timer(); + m_scriptTimer = new System.Timers.Timer(); m_scriptTimer.Enabled = true; m_scriptTimer.Interval = m_timeInterval*1000; m_scriptTimer.Elapsed += RunAutoTimerScript; diff --git a/bin/Mono.Posix.dll b/bin/Mono.Posix.dll new file mode 100755 index 0000000000000000000000000000000000000000..97ec8bf3f272f87c5b83ecabc37101b2f3eb0b84 GIT binary patch literal 207872 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

wh3F&xmBb#e>OU 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 j8l{|CW5 B&`AIQ literal 0 HcmV?d00001 diff --git a/prebuild.xml b/prebuild.xml index 2bb053ec51..cb39e18e16 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1790,6 +1790,7 @@ + From da2c1e8aadd3de2821e1aa1e002259876077d271 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 12 Dec 2016 00:54:41 +0000 Subject: [PATCH 158/305] don't do unix signals on windows --- OpenSim/Region/Application/OpenSim.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 203fe5ec8b..aba09e03c0 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -126,11 +126,8 @@ namespace OpenSim m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod); } - private static Mono.Unix.UnixSignal[] signals = new Mono.Unix.UnixSignal[] - { -// new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGINT), - new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGTERM) - }; + private static Mono.Unix.UnixSignal[] signals; + private Thread signal_thread = new Thread (delegate () { @@ -154,7 +151,16 @@ namespace OpenSim m_log.Info("========================= STARTING OPENSIM ========================="); m_log.Info("===================================================================="); - signal_thread.Start(); + if(!Util.IsWindows()) + { + // linux mac os specifics + signals = new Mono.Unix.UnixSignal[] + { +// new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGINT), + new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGTERM) + }; + signal_thread.Start(); + } //m_log.InfoFormat("[OPENSIM MAIN]: GC Is Server GC: {0}", GCSettings.IsServerGC.ToString()); // http://msdn.microsoft.com/en-us/library/bb384202.aspx //GCSettings.LatencyMode = GCLatencyMode.Batch; From cdfdf6322defc614a1261a38c710bf3f73cd4dc7 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Mon, 12 Dec 2016 09:26:12 +0000 Subject: [PATCH 159/305] Applying a modified version of TomTheDragon's patch to prevent the sim from crashing when signals are unavailable. --- OpenSim/Region/Application/OpenSim.cs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index aba09e03c0..3cb999bee5 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -131,7 +131,6 @@ namespace OpenSim private Thread signal_thread = new Thread (delegate () { - System.Console.WriteLine("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"); while (true) { // Wait for a signal to be delivered @@ -153,13 +152,21 @@ namespace OpenSim if(!Util.IsWindows()) { - // linux mac os specifics - signals = new Mono.Unix.UnixSignal[] + try { -// new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGINT), - new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGTERM) - }; - signal_thread.Start(); + // linux mac os specifics + signals = new Mono.Unix.UnixSignal[] + { + new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGTERM) + }; + signal_thread.Start(); + } + catch (Exception e) + { + m_log.Info("Could not set up UNIX signal handlers. SIGTERM will not"); + m_log.InfoFormat("shut down gracefully: {0}", e.Message); + m_log.Debug("Exception was: ", e); + } } //m_log.InfoFormat("[OPENSIM MAIN]: GC Is Server GC: {0}", GCSettings.IsServerGC.ToString()); // http://msdn.microsoft.com/en-us/library/bb384202.aspx From 9ef9dde0f3ea9185bb9aca03d173e5312e1ba308 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Mon, 12 Dec 2016 10:08:31 +0000 Subject: [PATCH 160/305] Make resolving the IP on startup optional. Adds ResolveAddress boolean to regions.ini --- OpenSim/Framework/RegionInfo.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index f764a347f6..d7a51ec975 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -147,6 +147,7 @@ namespace OpenSim.Framework public string RemotingAddress; public UUID ScopeID = UUID.Zero; private UUID m_maptileStaticUUID = UUID.Zero; + private bool m_resolveAddress = false; public uint WorldLocX = 0; public uint WorldLocY = 0; @@ -686,6 +687,20 @@ namespace OpenSim.Framework config.Set("AllowAlternatePorts", m_allow_alternate_ports.ToString()); } + // ResolveAddress + // + allKeys.Remove("ResolveAddress"); + if (config.Contains("ResolveAddress")) + { + m_resolveAddress = config.GetBoolean("ResolveAddress", false); + } + else + { + m_resolveAddress = Convert.ToBoolean(MainConsole.Instance.CmdPrompt("Resolve hostname to IP on start (for running inside Docker)", "False")); + + config.Set("ResolveAddress", m_resolveAddress.ToString()); + } + // ExternalHostName // allKeys.Remove("ExternalHostName"); @@ -706,6 +721,10 @@ namespace OpenSim.Framework "[REGIONINFO]: Resolving SYSTEMIP to {0} for external hostname of region {1}", m_externalHostName, name); } + else if (!m_resolveAddress) + { + m_externalHostName = externalName; + } else { IPAddress[] addrs = Dns.GetHostAddresses(externalName); From bebfbd0600671a34e87303dc6ba34e994182f993 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Mon, 12 Dec 2016 10:14:16 +0000 Subject: [PATCH 161/305] Only ask for the new parameter when starting from scratch. It is set to false implicitly on existing regions. --- OpenSim/Framework/RegionInfo.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index d7a51ec975..adffe13237 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -545,7 +545,7 @@ namespace OpenSim.Framework private void ReadNiniConfig(IConfigSource source, string name) { -// bool creatingNew = false; + bool creatingNew = false; if (source.Configs.Count == 0) { @@ -569,7 +569,7 @@ namespace OpenSim.Framework source.AddConfig(name); -// creatingNew = true; + creatingNew = true; } if (name == String.Empty) @@ -696,7 +696,8 @@ namespace OpenSim.Framework } else { - m_resolveAddress = Convert.ToBoolean(MainConsole.Instance.CmdPrompt("Resolve hostname to IP on start (for running inside Docker)", "False")); + if (creatingNew) + m_resolveAddress = Convert.ToBoolean(MainConsole.Instance.CmdPrompt("Resolve hostname to IP on start (for running inside Docker)", "False")); config.Set("ResolveAddress", m_resolveAddress.ToString()); } From 1388ac2ef7d774b4d25f18d237fdad89d7ac43ac Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Mon, 12 Dec 2016 11:09:38 +0000 Subject: [PATCH 162/305] Rename charterMember to membershipType to show what it actually is. This field started out as a simple flag in the protocol to indicate a user being a SL charter member. It has since then taken on additional functionality that means that the name is no longer appropriate. --- OpenSim/Framework/IClientAPI.cs | 2 +- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 4 ++-- .../CoreModules/Avatar/Profile/BasicProfileModule.cs | 4 ++-- .../Avatar/UserProfiles/UserProfileModule.cs | 12 ++++++------ .../InternetRelayClientView/Server/IRCClientView.cs | 2 +- .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 2 +- .../Services/Connectors/SimianGrid/SimianProfiles.cs | 8 ++++---- OpenSim/Tests/Common/Mock/TestClient.cs | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index f1290b9a2a..c4de81e93a 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -1293,7 +1293,7 @@ namespace OpenSim.Framework void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks); void SendViewerTime(int phase); - void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, string flAbout, + void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] membershipType, string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, UUID partnerID); void SendScriptQuestion(UUID taskID, string taskName, string ownerName, UUID itemID, int question); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index ce7ee98d9b..a69b670cd7 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -2704,7 +2704,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, ThrottleOutPacketType.Task); } - public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, + public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] membershipType, string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, UUID partnerID) { @@ -2716,7 +2716,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP else avatarReply.PropertiesData.AboutText = Utils.EmptyBytes; avatarReply.PropertiesData.BornOn = Util.StringToBytes256(bornOn); - avatarReply.PropertiesData.CharterMember = charterMember; + avatarReply.PropertiesData.CharterMember = membershipType; if (flAbout != null) avatarReply.PropertiesData.FLAboutText = Util.StringToBytes256(flAbout); else diff --git a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs index 2bb24ae880..0b1dbc71ca 100644 --- a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs @@ -154,7 +154,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile name = account.FirstName + " " + account.LastName; created = account.Created; } - Byte[] charterMember = Utils.StringToBytes(name); + Byte[] membershipType = Utils.StringToBytes(name); profileUrl = "No profile data"; aboutText = string.Empty; @@ -166,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile remoteClient.SendAvatarProperties(avatarID, aboutText, Util.ToDateTime(created).ToString( "M/d/yyyy", CultureInfo.InvariantCulture), - charterMember, firstLifeAboutText, + membershipType, firstLifeAboutText, (uint)(0 & 0xff), firstLifeImage, image, profileUrl, partner); diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 7d68299cd5..ce5816bf9b 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -1032,7 +1032,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles userInfo = new Dictionary(); } - Byte[] charterMember = new Byte[1]; + Byte[] membershipType = new Byte[1]; string born = String.Empty; uint flags = 0x00; @@ -1040,11 +1040,11 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if (account.UserTitle == "") { - charterMember[0] = (Byte)((account.UserFlags & 0xf00) >> 8); + membershipType[0] = (Byte)((account.UserFlags & 0xf00) >> 8); } else { - charterMember = Utils.StringToBytes(account.UserTitle); + membershipType = Utils.StringToBytes(account.UserTitle); } born = Util.ToDateTime(account.Created).ToString( @@ -1057,11 +1057,11 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if ((string)userInfo["user_title"] == "") { - charterMember[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8); + membershipType[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8); } else { - charterMember = Utils.StringToBytes((string)userInfo["user_title"]); + membershipType = Utils.StringToBytes((string)userInfo["user_title"]); } int val_born = (int)userInfo["user_created"]; @@ -1085,7 +1085,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } - remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, charterMember , props.FirstLifeText, flags, + remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType , props.FirstLifeText, flags, props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 15d31bddbb..8b8ebe0915 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -1247,7 +1247,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, byte[] charterMember, string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, UUID partnerID) + public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, byte[] membershipType, string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, UUID partnerID) { } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index b904353611..a929e80602 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -981,7 +981,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, + public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] membershipType, string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, UUID partnerID) { diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs index 8fc766d9e0..17f4fc694b 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs @@ -308,11 +308,11 @@ namespace OpenSim.Services.Connectors.SimianGrid about = new OSDMap(0); // Check if this user is a grid operator - byte[] charterMember; + byte[] membershipType; if (user["AccessLevel"].AsInteger() >= 200) - charterMember = Utils.StringToBytes("Operator"); + membershipType = Utils.StringToBytes("Operator"); else - charterMember = Utils.EmptyBytes; + membershipType = Utils.EmptyBytes; // Check if the user is online if (client.Scene is Scene) @@ -327,7 +327,7 @@ namespace OpenSim.Services.Connectors.SimianGrid flags |= ProfileFlags.Identified; client.SendAvatarProperties(avatarID, about["About"].AsString(), user["CreationDate"].AsDate().ToString("M/d/yyyy", - System.Globalization.CultureInfo.InvariantCulture), charterMember, about["FLAbout"].AsString(), (uint)flags, + System.Globalization.CultureInfo.InvariantCulture), membershipType, about["FLAbout"].AsString(), (uint)flags, about["FLImage"].AsUUID(), about["Image"].AsUUID(), about["URL"].AsString(), user["Partner"].AsUUID()); OSDMap interests = null; diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 9251c4fcd3..f407e5a7c1 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -990,7 +990,7 @@ namespace OpenSim.Tests.Common { } - public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, + public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] membershipType, string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, UUID partnerID) { From fe3303dc110b4932717031278d64ab2e6900e99b Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 12 Dec 2016 17:53:40 +0000 Subject: [PATCH 163/305] ubOde simple spheres and boxes with type convex have no holes on physics(long forgotten fix) --- .../PhysicsModules/ubOde/ODEMeshWorker.cs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODEMeshWorker.cs b/OpenSim/Region/PhysicsModules/ubOde/ODEMeshWorker.cs index a9774730e6..5a3008d09a 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODEMeshWorker.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODEMeshWorker.cs @@ -239,7 +239,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde { if (m_scene.haveActor(repData.actor)) { - if (needsMeshing(repData.pbs)) // no need for pbs now? + if (needsMeshing(repData)) // no need for pbs now? { repData.comand = meshWorkerCmnds.changefull; createqueue.Enqueue(repData); @@ -284,8 +284,9 @@ namespace OpenSim.Region.PhysicsModule.ubOde ///

/// /// - public bool needsMeshing(PrimitiveBaseShape pbs) + public bool needsMeshing(ODEPhysRepData repData) { + PrimitiveBaseShape pbs = repData.pbs; // check sculpts or meshs if (pbs.SculptEntry) { @@ -301,6 +302,11 @@ namespace OpenSim.Region.PhysicsModule.ubOde if (forceSimplePrimMeshing) return true; + // convex shapes have no holes + ushort profilehollow = pbs.ProfileHollow; + if(repData.shapetype == 2) + profilehollow = 0; + // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) @@ -309,7 +315,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde { if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 - && pbs.ProfileHollow == 0 + && profilehollow == 0 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 && pbs.PathBegin == 0 && pbs.PathEnd == 0 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 @@ -326,7 +332,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde int iPropertiesNotSupportedDefault = 0; - if (pbs.ProfileHollow != 0) + if (profilehollow != 0) iPropertiesNotSupportedDefault++; if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) @@ -407,7 +413,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde PhysicsActor actor = repData.actor; PrimitiveBaseShape pbs = repData.pbs; - if (!needsMeshing(pbs)) + if (!needsMeshing(repData)) { repData.meshState = MeshState.noNeed; repData.hasOBB = false; @@ -417,16 +423,16 @@ namespace OpenSim.Region.PhysicsModule.ubOde IMesh mesh = null; Vector3 size = repData.size; - byte shapetype = repData.shapetype; - - bool convex; int clod = (int)LevelOfDetail.High; + bool convex; + byte shapetype = repData.shapetype; if (shapetype == 0) convex = false; else { convex = true; + // sculpts pseudo convex if (pbs.SculptType != (byte)SculptType.Mesh) clod = (int)LevelOfDetail.Low; } @@ -483,7 +489,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde repData.mesh = null; repData.hasOBB = false; - if (!needsMeshing(pbs)) + if (!needsMeshing(repData)) { repData.meshState = MeshState.noNeed; return; From 7d8cb244d1148d70b43c51add04e095bd1160cd7 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 12 Dec 2016 19:16:51 +0000 Subject: [PATCH 164/305] ubOde other convex type objects other than mesh and sculpt also don't have holes --- OpenSim/Region/PhysicsModules/ubOde/ODEMeshWorker.cs | 2 +- .../Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODEMeshWorker.cs b/OpenSim/Region/PhysicsModules/ubOde/ODEMeshWorker.cs index 5a3008d09a..bb661e54ad 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODEMeshWorker.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODEMeshWorker.cs @@ -433,7 +433,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde { convex = true; // sculpts pseudo convex - if (pbs.SculptType != (byte)SculptType.Mesh) + if (pbs.SculptEntry && pbs.SculptType != (byte)SculptType.Mesh) clod = (int)LevelOfDetail.Low; } diff --git a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs index 2ae0881e78..7f0713a7c3 100644 --- a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs +++ b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs @@ -349,7 +349,7 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing } else { - if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, lod, out coords, out faces)) + if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, lod, convex, out coords, out faces)) return null; } @@ -942,7 +942,8 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing /// Faces are added to this list by the method. /// true if coords and faces were successfully generated, false if not private bool GenerateCoordsAndFacesFromPrimShapeData( - string primName, PrimitiveBaseShape primShape, float lod, out List coords, out List faces) + string primName, PrimitiveBaseShape primShape, float lod, bool convex, + out List coords, out List faces) { PrimMesh primMesh; coords = new List(); @@ -970,7 +971,9 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing profileBegin = profileEnd - 0.02f; float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f; - if (profileHollow > 0.95f) + if(convex) + profileHollow = 0.0f; + else if (profileHollow > 0.95f) profileHollow = 0.95f; int sides = 4; From ee58beddece251f58e3befb0b6aa7f78d5ab372b Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Tue, 13 Dec 2016 14:43:10 +0000 Subject: [PATCH 165/305] Make sure sims on Linux can be restarted without waiting on a 2 mintue socket timeout --- .../Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 4d726b43dd..fffd02c347 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -217,10 +217,6 @@ namespace OpenMetaverse SocketType.Dgram, ProtocolType.Udp); - // OpenSim may need this but in AVN, this messes up automated - // sim restarts badly - //m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); - try { if (m_udpSocket.Ttl < 128) @@ -248,7 +244,13 @@ namespace OpenMetaverse // we never want two regions to listen on the same port as they cannot demultiplex each other's messages, // leading to a confusing bug. // By default, Windows does not allow two sockets to bind to the same port. - m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); + // + // Unfortunately, this also causes a crashed sim to leave the socket in a state + // where it appears to be in use but is really just hung from the old process + // crashing rather than closing it. While this protects agains misconfiguration, + // allowing crashed sims to be started up again right away, rather than having to + // wait 2 minutes for the socket to clear is more valuable. Commented 12/13/2016 + // m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); if (recvBufferSize != 0) m_udpSocket.ReceiveBufferSize = recvBufferSize; From 69776aa70ce662ccd0ad3d9f2ecefb86671bbcb3 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Tue, 13 Dec 2016 19:47:26 +0000 Subject: [PATCH 166/305] Remove the AllowAlternatePorts option. It wasn't implemented anyway. Instead, handle the port being 0 as "any port" and assign a random port for regions in that case. --- OpenSim/Framework/RegionInfo.cs | 34 ++----------------- .../ClientStack/Linden/UDP/LLUDPServer.cs | 11 +++--- .../ClientStack/Linden/UDP/OpenSimUDPBase.cs | 8 +++++ .../Common/Helpers/ClientStackHelpers.cs | 4 +-- OpenSim/Tests/Common/Mock/TestLLUDPServer.cs | 4 +-- 5 files changed, 21 insertions(+), 40 deletions(-) diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index adffe13237..8f754a5ef2 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -138,8 +138,6 @@ namespace OpenSim.Framework protected uint m_httpPort; protected string m_serverURI; protected string m_regionName = String.Empty; - protected bool Allow_Alternate_Ports; - public bool m_allow_alternate_ports; protected string m_externalHostName; protected IPEndPoint m_internalEndPoint; protected uint m_remotingPort; @@ -673,20 +671,6 @@ namespace OpenSim.Framework } m_internalEndPoint = new IPEndPoint(address, port); - // AllowAlternatePorts - // - allKeys.Remove("AllowAlternatePorts"); - if (config.Contains("AllowAlternatePorts")) - { - m_allow_alternate_ports = config.GetBoolean("AllowAlternatePorts", true); - } - else - { - m_allow_alternate_ports = Convert.ToBoolean(MainConsole.Instance.CmdPrompt("Allow alternate ports", "False")); - - config.Set("AllowAlternatePorts", m_allow_alternate_ports.ToString()); - } - // ResolveAddress // allKeys.Remove("ResolveAddress"); @@ -925,8 +909,6 @@ namespace OpenSim.Framework config.Set("InternalAddress", m_internalEndPoint.Address.ToString()); config.Set("InternalPort", m_internalEndPoint.Port); - config.Set("AllowAlternatePorts", m_allow_alternate_ports.ToString()); - config.Set("ExternalHostName", m_externalHostName); if (m_nonphysPrimMin > 0) @@ -1019,10 +1001,6 @@ namespace OpenSim.Framework configMember.addConfigurationOption("internal_ip_port", ConfigurationOption.ConfigurationTypes.TYPE_INT32, "Internal IP Port for incoming UDP client connections", m_internalEndPoint.Port.ToString(), true); - configMember.addConfigurationOption("allow_alternate_ports", - ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN, - "Allow sim to find alternate UDP ports when ports are in use?", - m_allow_alternate_ports.ToString(), true); configMember.addConfigurationOption("external_host_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "External Host Name", m_externalHostName, true); @@ -1092,9 +1070,6 @@ namespace OpenSim.Framework configMember.addConfigurationOption("internal_ip_port", ConfigurationOption.ConfigurationTypes.TYPE_INT32, "Internal IP Port for incoming UDP client connections", ConfigSettings.DefaultRegionHttpPort.ToString(), false); - configMember.addConfigurationOption("allow_alternate_ports", ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN, - "Allow sim to find alternate UDP ports when ports are in use?", - "false", true); configMember.addConfigurationOption("external_host_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "External Host Name", "127.0.0.1", false); @@ -1165,9 +1140,6 @@ namespace OpenSim.Framework case "internal_ip_port": m_internalEndPoint.Port = (int) configuration_result; break; - case "allow_alternate_ports": - m_allow_alternate_ports = (bool) configuration_result; - break; case "external_host_name": if ((string) configuration_result != "SYSTEMIP") { @@ -1244,7 +1216,6 @@ namespace OpenSim.Framework if ((RemotingAddress != null) && !RemotingAddress.Equals("")) args["remoting_address"] = OSD.FromString(RemotingAddress); args["remoting_port"] = OSD.FromString(RemotingPort.ToString()); - args["allow_alt_ports"] = OSD.FromBoolean(m_allow_alternate_ports); if ((proxyUrl != null) && !proxyUrl.Equals("")) args["proxy_url"] = OSD.FromString(proxyUrl); if (RegionType != String.Empty) @@ -1299,8 +1270,6 @@ namespace OpenSim.Framework RemotingAddress = args["remoting_address"].AsString(); if (args["remoting_port"] != null) UInt32.TryParse(args["remoting_port"].AsString(), out m_remotingPort); - if (args["allow_alt_ports"] != null) - m_allow_alternate_ports = args["allow_alt_ports"].AsBoolean(); if (args["proxy_url"] != null) proxyUrl = args["proxy_url"].AsString(); if (args["region_type"] != null) @@ -1338,7 +1307,8 @@ namespace OpenSim.Framework kvp["http_port"] = HttpPort.ToString(); kvp["internal_ip_address"] = InternalEndPoint.Address.ToString(); kvp["internal_port"] = InternalEndPoint.Port.ToString(); - kvp["alternate_ports"] = m_allow_alternate_ports.ToString(); + // TODO: Remove in next major version + kvp["alternate_ports"] = "False"; kvp["server_uri"] = ServerURI; return kvp; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index a868e3aa44..cedb9b4fec 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -81,7 +81,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP uint port = (uint)scene.RegionInfo.InternalEndPoint.Port; IPAddress listenIP = scene.RegionInfo.InternalEndPoint.Address; - Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, scene.RegionInfo.m_allow_alternate_ports, m_Config, scene.AuthenticateHandler); + Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, m_Config, scene.AuthenticateHandler); scene.RegionInfo.InternalEndPoint.Port = (int)port; AddScene(scene); @@ -98,9 +98,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP } #endregion - public virtual void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) + public virtual void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, IConfigSource configSource, AgentCircuitManager circuitManager) { - m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); + m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, configSource, circuitManager); } public virtual void AddScene(IScene scene) @@ -430,12 +430,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP public JobEngine OqrEngine { get; protected set; } public LLUDPServer( - IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, + IPAddress listenIP, ref uint port, int proxyPortOffsetParm, IConfigSource configSource, AgentCircuitManager circuitManager) : base(listenIP, (int)port) { #region Environment.TickCount Measurement + // Update the port with the one we actually got + port = (uint)Port; + // Measure the resolution of Environment.TickCount TickCountResolution = 0f; for (int i = 0; i < 10; i++) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index fffd02c347..831381e8ce 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -107,6 +107,11 @@ namespace OpenMetaverse ///
public float AverageReceiveTicksForLastSamplePeriod { get; private set; } + public int Port + { + get { return m_udpPort; } + } + #region PacketDropDebugging /// /// For debugging purposes only... random number generator for dropping @@ -257,6 +262,9 @@ namespace OpenMetaverse m_udpSocket.Bind(ipep); + if (m_udpPort == 0) + m_udpPort = ((IPEndPoint)m_udpSocket.LocalEndPoint).Port; + IsRunningInbound = true; // kick off an async receive. The Start() method will return, the diff --git a/OpenSim/Tests/Common/Helpers/ClientStackHelpers.cs b/OpenSim/Tests/Common/Helpers/ClientStackHelpers.cs index 33cd8a2cd4..df9f6f22c8 100644 --- a/OpenSim/Tests/Common/Helpers/ClientStackHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/ClientStackHelpers.cs @@ -86,10 +86,10 @@ namespace OpenSim.Tests.Common uint port = 0; AgentCircuitManager acm = scene.AuthenticateHandler; - TestLLUDPServer udpServer = new TestLLUDPServer(IPAddress.Any, ref port, 0, false, configSource, acm); + TestLLUDPServer udpServer = new TestLLUDPServer(IPAddress.Any, ref port, 0, configSource, acm); udpServer.AddScene(scene); return udpServer; } } -} \ No newline at end of file +} diff --git a/OpenSim/Tests/Common/Mock/TestLLUDPServer.cs b/OpenSim/Tests/Common/Mock/TestLLUDPServer.cs index 26887c9ebd..b2c6a8cc4c 100644 --- a/OpenSim/Tests/Common/Mock/TestLLUDPServer.cs +++ b/OpenSim/Tests/Common/Mock/TestLLUDPServer.cs @@ -43,8 +43,8 @@ namespace OpenSim.Tests.Common { public List PacketsSent { get; private set; } - public TestLLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) - : base(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager) + public TestLLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, IConfigSource configSource, AgentCircuitManager circuitManager) + : base(listenIP, ref port, proxyPortOffsetParm, configSource, circuitManager) { PacketsSent = new List(); } From ec883d0f1504e8573f763882231cb1da06bdc2a1 Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Wed, 14 Dec 2016 01:14:23 +0100 Subject: [PATCH 167/305] New OSSL function: osNpcSetProfileImage(LSL_Key npc, string image); This patch gives possibility to set image in created NPC's profile. You can use UUID of the texture or name of texture included in prim's inventory. Signed-off-by: Mandarinka Tasty Signed-off-by: UbitUmarov --- .../Avatar/UserProfiles/UserProfileModule.cs | 2 +- .../Region/Framework/Interfaces/INPCModule.cs | 1 + .../OptionalModules/World/NPC/NPCAvatar.cs | 8 +++++ .../Shared/Api/Implementation/OSSL_Api.cs | 29 +++++++++++++++++++ .../Shared/Api/Interface/IOSSL_Api.cs | 1 + .../Shared/Api/Runtime/OSSL_Stub.cs | 5 ++++ 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index ce5816bf9b..5314927c17 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -1011,7 +1011,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { remoteClient.SendAvatarProperties(avatarID, ((INPC)(p.ControllingClient)).profileAbout, ((INPC)(p.ControllingClient)).Born, Utils.StringToBytes("Non Player Character (NPC)"), "NPCs have no life", 16, - UUID.Zero, UUID.Zero, "", UUID.Zero); + UUID.Zero, ((INPC)(p.ControllingClient)).profileImage, "", UUID.Zero); remoteClient.SendAvatarInterestsReply(avatarID, 0, "", 0, "Getting into trouble", "Droidspeak"); return; diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs index dd4226cde7..813be4f93e 100644 --- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs +++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs @@ -59,6 +59,7 @@ namespace OpenSim.Region.Framework.Interfaces UUID ActiveGroupId { get; set; } UUID Owner { get; } string profileAbout { get; set; } + UUID profileImage { get; set; } string Born { get; set; } } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index a929e80602..0cabe47c0a 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -70,6 +70,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC private readonly UUID m_ownerID; private UUID m_hostGroupID; private string m_profileAbout = ""; + private UUID m_profileImage = UUID.Zero; private string m_born; public List SelectedObjects {get; private set;} @@ -110,6 +111,13 @@ namespace OpenSim.Region.OptionalModules.World.NPC m_profileAbout = value; } } + + public UUID profileImage + { + get { return m_profileImage; } + set { m_profileImage = value; } + } + public IScene Scene { get { return m_scene; } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index b101cf9b44..dd4da0a620 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -3018,6 +3018,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + public void osNpcSetProfileImage(LSL_Key npc, string image) + { + CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); + m_host.AddScriptLPS(1); + + INPCModule module = World.RequestModuleInterface(); + if (module != null) + { + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + UUID ImageID = new UUID(); + + ImageID = ScriptUtils.GetAssetIdFromItemName(m_host, image, (int)AssetType.Texture); + + if (ImageID == null || ImageID == UUID.Zero) + { + if (!UUID.TryParse(image, out ImageID)) + return; + } + + ScenePresence sp = World.GetScenePresence(npcId); + if (sp != null) + ((INPC)(sp.ControllingClient)).profileImage = ImageID; + } + } + public void osNpcSay(LSL_Key npc, string message) { osNpcSay(npc, 0, message); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 87b09675b2..cf3e6df31d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -344,6 +344,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void osNpcSetRot(LSL_Key npc, rotation rot); void osNpcStopMoveToTarget(LSL_Key npc); void osNpcSetProfileAbout(LSL_Key npc, string about); + void osNpcSetProfileImage(LSL_Key npc, string image); void osNpcSay(key npc, string message); void osNpcSay(key npc, int channel, string message); void osNpcShout(key npc, int channel, string message); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index 5bc998e8c1..2e8a76c34e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -642,6 +642,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_OSSL_Functions.osNpcSetProfileAbout(npc, about); } + public void osNpcSetProfileImage(LSL_Key npc, string image) + { + m_OSSL_Functions.osNpcSetProfileImage(npc, image); + } + public void osNpcSay(key npc, string message) { m_OSSL_Functions.osNpcSay(npc, message); From a75c16e1bfee8679f61e513426e876635b3345cf Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Wed, 14 Dec 2016 01:00:48 +0000 Subject: [PATCH 168/305] Fox threat level line on SetProfileImage. It is ALWAYS the name of the function! Low is justified because setting an image requires having a NPC in the first place.... --- .../Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index dd4da0a620..a827e30137 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -3020,7 +3020,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcSetProfileImage(LSL_Key npc, string image) { - CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); + CheckThreatLevel(ThreatLevel.Low, "osNpcSetProfileImage"); m_host.AddScriptLPS(1); INPCModule module = World.RequestModuleInterface(); From 1c08b3d8f9e10ba11b70e99a92b7ca1272079a94 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 14 Dec 2016 01:16:21 +0000 Subject: [PATCH 169/305] also fox chekc threat level on osNpcSetProfileAbout --- .../Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index a827e30137..bdecf72c3b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -3001,7 +3001,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcSetProfileAbout(LSL_Key npc, string about) { - CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); + CheckThreatLevel(ThreatLevel.High, "osNpcSetProfileAbout"); m_host.AddScriptLPS(1); INPCModule module = World.RequestModuleInterface(); From 1ffc81c8690b039a578155fb76bbbd2307ae3ebc Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 14 Dec 2016 01:31:16 +0000 Subject: [PATCH 170/305] also reduce check threat level of osNpcSetProfileAbout to Low; update osslEnable.ini --- .../Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 2 +- bin/config-include/osslEnable.ini | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index bdecf72c3b..9742119d66 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -3001,7 +3001,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcSetProfileAbout(LSL_Key npc, string about) { - CheckThreatLevel(ThreatLevel.High, "osNpcSetProfileAbout"); + CheckThreatLevel(ThreatLevel.Low, "osNpcSetProfileAbout"); m_host.AddScriptLPS(1); INPCModule module = World.RequestModuleInterface(); diff --git a/bin/config-include/osslEnable.ini b/bin/config-include/osslEnable.ini index 4c6be1604c..59a162a98d 100644 --- a/bin/config-include/osslEnable.ini +++ b/bin/config-include/osslEnable.ini @@ -139,6 +139,8 @@ Allow_osMessageObject = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER Allow_osRegexIsMatch = true Allow_osGetAvatarHomeURI = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER + Allow_osNpcSetProfileAbout = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER + Allow_osNpcSetProfileImage = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER ; ThreatLevel Moderate Allow_osDropAttachment = ${XEngine|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER From 364d58635ba4479d4eb267a4b021cc2be211bbde Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 14 Dec 2016 03:02:57 +0000 Subject: [PATCH 171/305] avoid a null ref --- OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs index 5c791e6e76..eb2867d548 100644 --- a/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs +++ b/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs @@ -268,8 +268,12 @@ namespace OpenSim.Region.DataSnapshot.Providers { XmlNode username = nodeFactory.CreateNode(XmlNodeType.Element, "name", ""); UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, userOwnerUUID); - username.InnerText = account.FirstName + " " + account.LastName; + if(account != null) + username.InnerText = account.FirstName + " " + account.LastName; + else + username.InnerText = "UnKnown"; userblock.AppendChild(username); + } catch (Exception) { From 50842347ace4f9ada316364d08ccc0675901f84b Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 14 Dec 2016 04:00:48 +0000 Subject: [PATCH 172/305] fix: check for region_handle before region_id, viewers are so funny.. --- .../World/Land/LandManagementModule.cs | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 98f1f3bd44..bec5322341 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -72,8 +72,6 @@ namespace OpenSim.Region.CoreModules.World.Land public const int LandUnit = 4; - private static readonly string remoteParcelRequestPath = "0009/"; - private LandChannel landChannel; private Scene m_scene; @@ -1682,12 +1680,13 @@ namespace OpenSim.Region.CoreModules.World.Land private void EventManagerOnRegisterCaps(UUID agentID, Caps caps) { + //string capsBase = "/CAPS/" + UUID.Random(); string capsBase = "/CAPS/" + caps.CapsObjectPath; caps.RegisterHandler( "RemoteParcelRequest", new RestStreamHandler( "POST", - capsBase + remoteParcelRequestPath, + capsBase, (request, path, param, httpRequest, httpResponse) => RemoteParcelRequest(request, path, param, agentID, caps), "RemoteParcelRequest", @@ -1807,24 +1806,7 @@ namespace OpenSim.Region.CoreModules.World.Land ArrayList list = (ArrayList)hash["location"]; uint x = (uint)(double)list[0]; uint y = (uint)(double)list[1]; - if(hash.ContainsKey("region_id")) - { - UUID regionID = (UUID)hash["region_id"]; - if (regionID == m_scene.RegionInfo.RegionID) - { - // a parcel request for a local parcel => no need to query the grid - parcelID = Util.BuildFakeParcelID(m_scene.RegionInfo.RegionHandle, x, y); - } - else - { - // a parcel request for a parcel in another region. Ask the grid about the region - GridRegion info = m_scene.GridService.GetRegionByUUID(scope, regionID); - if (info != null) - parcelID = Util.BuildFakeParcelID(info.RegionHandle, x, y); - } - } - - else if (hash.ContainsKey("region_handle")) + if (hash.ContainsKey("region_handle")) { // if you do a "About Landmark" on a landmark a second time, the viewer sends the // region_handle it got earlier via RegionHandleRequest @@ -1847,6 +1829,24 @@ namespace OpenSim.Region.CoreModules.World.Land } } } + else if(hash.ContainsKey("region_id")) + { + UUID regionID = (UUID)hash["region_id"]; + if (regionID == m_scene.RegionInfo.RegionID) + { + // a parcel request for a local parcel => no need to query the grid + parcelID = Util.BuildFakeParcelID(m_scene.RegionInfo.RegionHandle, x, y); + } + else + { + // a parcel request for a parcel in another region. Ask the grid about the region + GridRegion info = m_scene.GridService.GetRegionByUUID(scope, regionID); + if (info != null) + parcelID = Util.BuildFakeParcelID(info.RegionHandle, x, y); + } + } + + } } catch (LLSD.LLSDParseException e) From 7a31a854083bb9345bbc184e8187fa662e21c5f5 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 14 Dec 2016 14:48:50 +0000 Subject: [PATCH 173/305] show online on profile, if target is in same region.( possible should be done elsewhere) --- .../CoreModules/Avatar/UserProfiles/UserProfileModule.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 5314927c17..c505d949ef 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -1010,7 +1010,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (p != null && p.isNPC) { remoteClient.SendAvatarProperties(avatarID, ((INPC)(p.ControllingClient)).profileAbout, ((INPC)(p.ControllingClient)).Born, - Utils.StringToBytes("Non Player Character (NPC)"), "NPCs have no life", 16, + Utils.StringToBytes("Non Player Character (NPC)"), "NPCs have no life", 0x10, UUID.Zero, ((INPC)(p.ControllingClient)).profileImage, "", UUID.Zero); remoteClient.SendAvatarInterestsReply(avatarID, 0, "", 0, "Getting into trouble", "Droidspeak"); @@ -1085,6 +1085,10 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } + // if on same region force online + if(p != null && !p.IsDeleted) + flags |= 0x10; + remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType , props.FirstLifeText, flags, props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); From 95d6396300d8788ac3b0e5a3ae2d184016eef9cc Mon Sep 17 00:00:00 2001 From: Jeff Kelley Date: Sun, 22 May 2016 00:57:30 +0200 Subject: [PATCH 174/305] Add osDie(key) Signed-off-by: UbitUmarov --- .../Shared/Api/Implementation/OSSL_Api.cs | 37 +++++++++++++++++++ .../Shared/Api/Interface/IOSSL_Api.cs | 7 ++++ .../Shared/Api/Runtime/OSSL_Stub.cs | 5 +++ 3 files changed, 49 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 9742119d66..8ecbaba6d1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -1874,6 +1874,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api "dataserver", resobj, new DetectParams[0])); } + + /// + /// Similar to llDie but given an object UUID + /// + /// + + public void osDie(LSL_Key objectUUID) + { + CheckThreatLevel(ThreatLevel.VeryHigh, "osDie"); + m_host.AddScriptLPS(1); + + UUID objUUID; + if (!UUID.TryParse(objectUUID, out objUUID)) // prior to patching, a thrown exception regarding invalid GUID format would be shouted instead. + { + OSSLShoutError("osDie() cannot delete objects with invalid UUIDs"); + return; + } + + DeleteObject(objUUID); + } + + private void DeleteObject(UUID objUUID) + { + SceneObjectGroup sceneOG = World.GetSceneObjectGroup(objUUID); + + if (sceneOG == null) // prior to patching, PostObjectEvent() would cause a throw exception to be shouted instead. + { + OSSLShoutError("osDie() cannot delete " + objUUID.ToString() + ", object was not found in scene."); + return; + } + + if (sceneOG.OwnerID != m_host.OwnerID) + return; + + World.DeleteSceneObject(sceneOG, false); + } + /// /// Write a notecard directly to the prim's inventory. /// diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index cf3e6df31d..7415fea6d8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -316,6 +316,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces /// void osForceBreakAllLinks(); + /// + /// Similar to llDie but given an object UUID + /// + /// + + void osDie(LSL_Key objectUUID); + /// /// Check if the given key is an npc /// diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index 2e8a76c34e..c34ccd0a21 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -577,6 +577,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_OSSL_Functions.osForceBreakAllLinks(); } + public void osDie(LSL_Key objectUUID) + { + m_OSSL_Functions.osDie(objectUUID); + } + public LSL_Integer osIsNpc(LSL_Key npc) { return m_OSSL_Functions.osIsNpc(npc); From 553b326fb2dda6650e5992c06213c54e1730347e Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 14 Dec 2016 16:08:25 +0000 Subject: [PATCH 175/305] restrict osDie to objects rezzed by the script object group and a few more changes --- .../Shared/Api/Implementation/OSSL_Api.cs | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 8ecbaba6d1..87fe2874cf 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -1882,33 +1882,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osDie(LSL_Key objectUUID) { - CheckThreatLevel(ThreatLevel.VeryHigh, "osDie"); +// CheckThreatLevel(ThreatLevel.VeryHigh, "osDie"); + // if this is restricted to objects rezzed by this host level can be reduced + + CheckThreatLevel(ThreatLevel.Low, "osDie"); m_host.AddScriptLPS(1); UUID objUUID; - if (!UUID.TryParse(objectUUID, out objUUID)) // prior to patching, a thrown exception regarding invalid GUID format would be shouted instead. + if (!UUID.TryParse(objectUUID, out objUUID)) { OSSLShoutError("osDie() cannot delete objects with invalid UUIDs"); return; } - DeleteObject(objUUID); - } + // harakiri check + if(objUUID == UUID.Zero) + throw new SelfDeleteException(); - private void DeleteObject(UUID objUUID) - { SceneObjectGroup sceneOG = World.GetSceneObjectGroup(objUUID); - if (sceneOG == null) // prior to patching, PostObjectEvent() would cause a throw exception to be shouted instead. - { - OSSLShoutError("osDie() cannot delete " + objUUID.ToString() + ", object was not found in scene."); + if (sceneOG == null || sceneOG.IsDeleted) + return; + + if(sceneOG.IsAttachment) return; - } if (sceneOG.OwnerID != m_host.OwnerID) return; + + // harakiri check + if(sceneOG.UUID == m_host.ParentGroup.UUID) + throw new SelfDeleteException(); - World.DeleteSceneObject(sceneOG, false); + // restrict to objects rezzed by host + if(sceneOG.RezzerID == m_host.ParentGroup.UUID) + World.DeleteSceneObject(sceneOG, false); } /// From 3056926403fb073d26ba11b3ebbcbd424a948dbf Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 14 Dec 2016 16:31:39 +0000 Subject: [PATCH 176/305] dont self osDie attachments --- .../ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 87fe2874cf..c83682ece5 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -1897,7 +1897,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // harakiri check if(objUUID == UUID.Zero) - throw new SelfDeleteException(); + { + if (!m_host.ParentGroup.IsAttachment) + throw new SelfDeleteException(); + return; + } SceneObjectGroup sceneOG = World.GetSceneObjectGroup(objUUID); From e2062951d7d374c6ee81a3eb20085c746dfa901c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 14 Dec 2016 16:33:52 +0000 Subject: [PATCH 177/305] update osslEnable.ini --- bin/config-include/osslEnable.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/config-include/osslEnable.ini b/bin/config-include/osslEnable.ini index 59a162a98d..0241280ebe 100644 --- a/bin/config-include/osslEnable.ini +++ b/bin/config-include/osslEnable.ini @@ -141,6 +141,7 @@ Allow_osGetAvatarHomeURI = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER Allow_osNpcSetProfileAbout = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER Allow_osNpcSetProfileImage = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER + Allow_osDie = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER ; ThreatLevel Moderate Allow_osDropAttachment = ${XEngine|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER From 1d6a7d2225a591e9a7f81e59378c5abf25767857 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 14 Dec 2016 22:34:27 +0000 Subject: [PATCH 178/305] correct the new npc entries in osslEnable.ini --- bin/config-include/osslEnable.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/config-include/osslEnable.ini b/bin/config-include/osslEnable.ini index 0241280ebe..a064f0957f 100644 --- a/bin/config-include/osslEnable.ini +++ b/bin/config-include/osslEnable.ini @@ -139,8 +139,8 @@ Allow_osMessageObject = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER Allow_osRegexIsMatch = true Allow_osGetAvatarHomeURI = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER - Allow_osNpcSetProfileAbout = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER - Allow_osNpcSetProfileImage = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER + Allow_osNpcSetProfileAbout = ${XEngine|osslNPC} + Allow_osNpcSetProfileImage = ${XEngine|osslNPC} Allow_osDie = ${XEngine|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER ; ThreatLevel Moderate From 1fd0178e8e1b1eda61898c87373a5234bd85fde4 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 15 Dec 2016 00:08:36 +0000 Subject: [PATCH 179/305] give regions a option to block profile web urls, so users are not sent to unknown web sites set by other users --- .../Avatar/UserProfiles/UserProfileModule.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index c505d949ef..1f7db64d98 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -69,6 +69,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles Dictionary m_classifiedInterest = new Dictionary(); private JsonRpcRequestManager rpc = new JsonRpcRequestManager(); + private bool m_allowUserProfileWebURLs = true; public Scene Scene { @@ -159,7 +160,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles Enabled = false; return; } - + + m_allowUserProfileWebURLs = profileConfig.GetBoolean("AllowUserProfileWebURLs", m_allowUserProfileWebURLs); m_log.Debug("[PROFILES]: Full Profiles Enabled"); ReplaceableInterface = null; Enabled = true; @@ -1089,6 +1091,10 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(p != null && !p.IsDeleted) flags |= 0x10; + + if(!m_allowUserProfileWebURLs) + props.WebUrl =""; + remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType , props.FirstLifeText, flags, props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); @@ -1119,6 +1125,9 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles prop.FirstLifeImageId = newProfile.FirstLifeImage; prop.FirstLifeText = newProfile.FirstLifeAboutText; + if(!m_allowUserProfileWebURLs) + prop.WebUrl =""; + string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); From 94a36396b13164252e85a39cb3160a5b56f9b4fd Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 15 Dec 2016 00:09:21 +0000 Subject: [PATCH 180/305] respective .ini settings --- bin/OpenSim.ini.example | 5 +++++ bin/OpenSimDefaults.ini | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index bb73687cda..557e47597f 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -1158,6 +1158,11 @@ ;; Set the value of the url to your UserProfilesService ;; If un-set / "" the module is disabled ;; ProfileServiceURL = ${Const|BaseURL}:${Const|PublicPort} + + ;# {AllowUserProfileWebURLs} {} {allow user profiles web urls} {true false} true + ;; set this to false to prevent your users to be sent to unkown + ;; web sites by other users on their profiles + ; AllowUserProfileWebURLs = true [XBakes] ;# {URL} {} {Set URL for Baked texture service} {} diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 3f8864e92f..b57a84437a 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -541,6 +541,10 @@ ;; points to your grid's Robust user profiles service ;; ; ProfileURL = http://127.0.0.1:9000 + + ;; set this to false to prevent your users to be sent to unkown + ;; web sites by other users on their profiles + ; AllowUserProfileWebURLs = true [SMTP] From 48efbeb8d346a104d673c69eeb03c70abf840178 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 15 Dec 2016 15:14:12 +0000 Subject: [PATCH 181/305] set pbs shape acording to mesh number of (material) faces --- .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 44 +++++++++++-------- bin/OpenSim.ini.example | 2 +- bin/OpenSimDefaults.ini | 2 +- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 6873325893..14a4873c1b 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -994,7 +994,6 @@ namespace OpenSim.Region.ClientStack.Linden pbs.TextureEntry = textureEntry.GetBytes(); - bool hasmesh = false; if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ... { int meshindx = inner_instance_list["mesh"].AsInteger(); @@ -1004,10 +1003,34 @@ namespace OpenSim.Region.ClientStack.Linden pbs.SculptType = (byte)SculptType.Mesh; pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction // data will be requested from asset on rez (i hope) - hasmesh = true; } } + // faces number to pbs shape + switch(face_list.Count) + { + case 1: + case 2: + pbs.ProfileCurve = (byte)ProfileCurve.Circle; + pbs.PathCurve = (byte)PathCurve.Circle; + break; + + case 3: + case 4: + pbs.ProfileCurve = (byte)ProfileCurve.Circle; + pbs.PathCurve = (byte)PathCurve.Line; + break; + case 5: + pbs.ProfileCurve = (byte)ProfileCurve.EqualTriangle; + pbs.PathCurve = (byte)PathCurve.Line; + break; + + default: + pbs.ProfileCurve = (byte)ProfileCurve.Square; + pbs.PathCurve = (byte)PathCurve.Line; + break; + } + Vector3 position = inner_instance_list["position"].AsVector3(); Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); @@ -1018,23 +1041,6 @@ namespace OpenSim.Region.ClientStack.Linden // int material = inner_instance_list["material"].AsInteger(); byte material = (byte)Material.Wood; -// no longer used - begin ------------------------ -// int mesh = inner_instance_list["mesh"].AsInteger(); - -// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; -// int base_mask = permissions["base_mask"].AsInteger(); -// int everyone_mask = permissions["everyone_mask"].AsInteger(); -// UUID creator_id = permissions["creator_id"].AsUUID(); -// UUID group_id = permissions["group_id"].AsUUID(); -// int group_mask = permissions["group_mask"].AsInteger(); -// bool is_owner_group = permissions["is_owner_group"].AsBoolean(); -// UUID last_owner_id = permissions["last_owner_id"].AsUUID(); -// int next_owner_mask = permissions["next_owner_mask"].AsInteger(); -// UUID owner_id = permissions["owner_id"].AsUUID(); -// int owner_mask = permissions["owner_mask"].AsInteger(); -// no longer used - end ------------------------ - - SceneObjectPart prim = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 557e47597f..5f1e779337 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -1160,7 +1160,7 @@ ;; ProfileServiceURL = ${Const|BaseURL}:${Const|PublicPort} ;# {AllowUserProfileWebURLs} {} {allow user profiles web urls} {true false} true - ;; set this to false to prevent your users to be sent to unkown + ;; set this to false to prevent your users to be sent to unknown ;; web sites by other users on their profiles ; AllowUserProfileWebURLs = true diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index b57a84437a..b133da9343 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -542,7 +542,7 @@ ;; ; ProfileURL = http://127.0.0.1:9000 - ;; set this to false to prevent your users to be sent to unkown + ;; set this to false to prevent your users to be sent to unknown ;; web sites by other users on their profiles ; AllowUserProfileWebURLs = true From c0a23d36dfa28a3204b31883e1e7bc76b249c8fb Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 15 Dec 2016 23:48:25 +0000 Subject: [PATCH 182/305] GetRegionsByName and GetHypergridRegionByName: detect that provided url is for local grid, and make it a local by region name local search --- OpenSim/Services/GridService/GridService.cs | 29 +++++++++++-------- .../Services/GridService/HypergridLinker.cs | 10 +++++++ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index 31a186ab3c..82b910ad93 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -508,6 +508,7 @@ namespace OpenSim.Services.GridService if(!m_HypergridLinker.buildHGRegionURI(name, out regionURI, out regionName)) return null; + bool localGrid = string.IsNullOrWhiteSpace(regionURI); string mapname = regionURI + regionName; bool haveMatch = false; @@ -531,7 +532,7 @@ namespace OpenSim.Services.GridService if(haveMatch) return rinfos; } - + rdatas = m_Database.Get(Util.EscapeForLike(mapname)+ "%", scopeID); if (rdatas != null && (rdatas.Count > 0)) { @@ -554,14 +555,16 @@ namespace OpenSim.Services.GridService if(haveMatch) return rinfos; } - - string HGname = regionURI +" "+ regionName; - GridRegion r = m_HypergridLinker.LinkRegion(scopeID, HGname); - if (r != null) + if(!localGrid) { - if( count == maxNumber) - rinfos.RemoveAt(count - 1); - rinfos.Add(r); + string HGname = regionURI +" "+ regionName; // include space for compatibility + GridRegion r = m_HypergridLinker.LinkRegion(scopeID, HGname); + if (r != null) + { + if( count == maxNumber) + rinfos.RemoveAt(count - 1); + rinfos.Add(r); + } } } else if (rdatas != null && (rdatas.Count > 0)) @@ -597,11 +600,13 @@ namespace OpenSim.Services.GridService if ((rdatas != null) && (rdatas.Count > 0)) return RegionData2RegionInfo(rdatas[0]); // get the first - string HGname = regionURI +" "+ regionName; - return m_HypergridLinker.LinkRegion(scopeID, HGname); + if(!string.IsNullOrWhiteSpace(regionURI)) + { + string HGname = regionURI +" "+ regionName; + return m_HypergridLinker.LinkRegion(scopeID, HGname); + } } - else - return null; + return null; } public List GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax) diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs index ceb2c6e7bb..185f2ff716 100644 --- a/OpenSim/Services/GridService/HypergridLinker.cs +++ b/OpenSim/Services/GridService/HypergridLinker.cs @@ -137,6 +137,12 @@ namespace OpenSim.Services.GridService m_log.WarnFormat("[HYPERGRID LINKER]: Malformed URL in [GridService], variable Gatekeeper = {0}", m_ThisGatekeeper); } + m_ThisGatekeeper = m_ThisGatekeeperURI.AbsoluteUri; + if(m_ThisGatekeeperURI.Port == 80) + m_ThisGatekeeper = m_ThisGatekeeper.Trim(new char[] { '/', ' ' }) +":80/"; + else if(m_ThisGatekeeperURI.Port == 443) + m_ThisGatekeeper = m_ThisGatekeeper.Trim(new char[] { '/', ' ' }) +":443/"; + m_GatekeeperConnector = new GatekeeperServiceConnector(m_AssetService); m_log.Debug("[HYPERGRID LINKER]: Loaded all services..."); @@ -302,6 +308,10 @@ namespace OpenSim.Services.GridService serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":80/"; else if(uri.Port == 443) serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":443/"; + + if(serverURI == m_ThisGatekeeper) + serverURI = ""; // local grid, look for region name only + return true; } From 853e98d3406df55832589091217ef14e27a23ea3 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 16 Dec 2016 01:13:07 +0000 Subject: [PATCH 183/305] reserve constant OBJECT_ATTACHED_SLOTS_AVAILABLE from mantis 8096. But do not implement it --- OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 734d878c86..903b362ea6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -643,6 +643,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OBJECT_REZZER_KEY = 32; public const int OBJECT_GROUP_TAG = 33; public const int OBJECT_TEMP_ATTACHED = 34; + public const int OBJECT_ATTACHED_SLOTS_AVAILABLE = 35; // Pathfinding types public const int OPT_OTHER = -1; From e2d46c060c4b9557cf596d6d828ddd296fa0af70 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 16 Dec 2016 03:38:20 +0000 Subject: [PATCH 184/305] ok.. another try on the HG uri --- OpenSim/Framework/Util.cs | 114 +++++++++++++++++ .../Grid/RemoteGridServiceConnector.cs | 27 +++- OpenSim/Services/GridService/GridService.cs | 25 +++- .../Services/GridService/HypergridLinker.cs | 121 +----------------- 4 files changed, 160 insertions(+), 127 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a6fd99f30f..5d8a5e0142 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -414,6 +414,120 @@ namespace OpenSim.Framework return regionCoord << 8; } + public static bool buildHGRegionURI(string inputName, out string serverURI, out string regionName) + { + serverURI = string.Empty; + regionName = string.Empty; + + inputName = inputName.Trim(); + + if (!inputName.StartsWith("http") && !inputName.StartsWith("https")) + { + // Formats: grid.example.com:8002:region name + // grid.example.com:region name + // grid.example.com:8002 + // grid.example.com + + string host; + uint port = 80; + + string[] parts = inputName.Split(new char[] { ':' }); + int indx; + if(parts.Length == 0) + return false; + if (parts.Length == 1) + { + indx = inputName.IndexOf('/'); + if (indx < 0) + serverURI = "http://"+ inputName + "/"; + else + { + serverURI = "http://"+ inputName.Substring(0,indx + 1); + if(indx + 2 < inputName.Length) + regionName = inputName.Substring(indx + 1); + } + } + else + { + host = parts[0]; + + if (parts.Length >= 2) + { + indx = parts[1].IndexOf('/'); + if(indx < 0) + { + // If it's a number then assume it's a port. Otherwise, it's a region name. + if (!UInt32.TryParse(parts[1], out port)) + { + port = 80; + regionName = parts[1]; + } + } + else + { + string portstr = parts[1].Substring(0, indx); + if(indx + 2 < parts[1].Length) + regionName = parts[1].Substring(indx + 1); + if (!UInt32.TryParse(portstr, out port)) + port = 80; + } + } + // always take the last one + if (parts.Length >= 3) + { + regionName = parts[2]; + } + + serverURI = "http://"+ host +":"+ port.ToString() + "/"; + } + } + else + { + // Formats: http://grid.example.com region name + // http://grid.example.com "region name" + // http://grid.example.com + + string[] parts = inputName.Split(new char[] { ' ' }); + + if (parts.Length == 0) + return false; + + serverURI = parts[0]; + + int indx = serverURI.LastIndexOf('/'); + if(indx > 10) + { + if(indx + 2 < inputName.Length) + regionName = inputName.Substring(indx + 1); + serverURI = inputName.Substring(0, indx + 1); + } + else if (parts.Length >= 2) + { + regionName = inputName.Substring(serverURI.Length); + } + } + + // use better code for sanity check + Uri uri; + try + { + uri = new Uri(serverURI); + } + catch + { + return false; + } + + if(!string.IsNullOrEmpty(regionName)) + regionName = regionName.Trim(new char[] { '"', ' ' }); + serverURI = uri.AbsoluteUri; + if(uri.Port == 80) + serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":80/"; + else if(uri.Port == 443) + serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":443/"; + return true; + } + public static T Clamp(T x, T min, T max) where T : IComparable { diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs index e6e3abb61e..f9ce5e1091 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs @@ -227,11 +227,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid return rinfo; } - public GridRegion GetRegionByName(UUID scopeID, string regionName) + public GridRegion GetRegionByName(UUID scopeID, string name) { - GridRegion rinfo = m_LocalGridService.GetRegionByName(scopeID, regionName); + GridRegion rinfo = m_LocalGridService.GetRegionByName(scopeID, name); if (rinfo != null) return rinfo; + + // HG urls should not get here, strip them + string regionName = name; + if(name.Contains(".")) + { + string regionURI = ""; + if(!Util.buildHGRegionURI(name, out regionURI, out regionName)) + return rinfo; + } rinfo = m_RemoteGridService.GetRegionByName(scopeID, regionName); m_RegionInfoCache.Cache(scopeID, rinfo); @@ -242,7 +251,19 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid { List rinfo = m_LocalGridService.GetRegionsByName(scopeID, name, maxNumber); //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: Local GetRegionsByName {0} found {1} regions", name, rinfo.Count); - List grinfo = m_RemoteGridService.GetRegionsByName(scopeID, name, maxNumber); + + // HG urls should not get here, strip them + // side effect is that local regions with same name as HG may also be found + // this mb good or bad + string regionName = name; + if(name.Contains(".")) + { + string regionURI = ""; + if(!Util.buildHGRegionURI(name, out regionURI, out regionName)) + return rinfo; + } + + List grinfo = m_RemoteGridService.GetRegionsByName(scopeID, regionName, maxNumber); if (grinfo != null) { diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index 82b910ad93..c51bb8b090 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -505,11 +505,16 @@ namespace OpenSim.Services.GridService { string regionURI = ""; string regionName = ""; - if(!m_HypergridLinker.buildHGRegionURI(name, out regionURI, out regionName)) + if(!Util.buildHGRegionURI(name, out regionURI, out regionName)) return null; - bool localGrid = string.IsNullOrWhiteSpace(regionURI); - string mapname = regionURI + regionName; + string mapname; + bool localGrid = m_HypergridLinker.IsLocalGrid(regionURI); + if(localGrid) + mapname = regionName; + else + mapname = regionURI + regionName; + bool haveMatch = false; if (rdatas != null && (rdatas.Count > 0)) @@ -555,7 +560,7 @@ namespace OpenSim.Services.GridService if(haveMatch) return rinfos; } - if(!localGrid) + if(!localGrid && !string.IsNullOrWhiteSpace(regionURI)) { string HGname = regionURI +" "+ regionName; // include space for compatibility GridRegion r = m_HypergridLinker.LinkRegion(scopeID, HGname); @@ -592,15 +597,21 @@ namespace OpenSim.Services.GridService { string regionURI = ""; string regionName = ""; - if(!m_HypergridLinker.buildHGRegionURI(name, out regionURI, out regionName)) + if(!Util.buildHGRegionURI(name, out regionURI, out regionName)) return null; - string mapname = regionURI + regionName; + string mapname; + bool localGrid = m_HypergridLinker.IsLocalGrid(regionURI); + if(localGrid) + mapname = regionName; + else + mapname = regionURI + regionName; + List rdatas = m_Database.Get(Util.EscapeForLike(mapname), scopeID); if ((rdatas != null) && (rdatas.Count > 0)) return RegionData2RegionInfo(rdatas[0]); // get the first - if(!string.IsNullOrWhiteSpace(regionURI)) + if(!localGrid && !string.IsNullOrWhiteSpace(regionURI)) { string HGname = regionURI +" "+ regionName; return m_HypergridLinker.LinkRegion(scopeID, HGname); diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs index 185f2ff716..aa394ce8e6 100644 --- a/OpenSim/Services/GridService/HypergridLinker.cs +++ b/OpenSim/Services/GridService/HypergridLinker.cs @@ -196,123 +196,10 @@ namespace OpenSim.Services.GridService { return TryLinkRegionToCoords(scopeID, mapName, xloc, yloc, UUID.Zero, out reason); } - - public bool buildHGRegionURI(string inputName, out string serverURI, out string regionName) + + public bool IsLocalGrid(string serverURI) { - serverURI = string.Empty; - regionName = string.Empty; - - inputName = inputName.Trim(); - - if (!inputName.StartsWith("http") && !inputName.StartsWith("https")) - { - // Formats: grid.example.com:8002:region name - // grid.example.com:region name - // grid.example.com:8002 - // grid.example.com - - string host; - uint port = 80; - - string[] parts = inputName.Split(new char[] { ':' }); - int indx; - if(parts.Length == 0) - return false; - if (parts.Length == 1) - { - indx = inputName.IndexOf('/'); - if (indx < 0) - serverURI = "http://"+ inputName + "/"; - else - { - serverURI = "http://"+ inputName.Substring(0,indx + 1); - if(indx + 2 < inputName.Length) - regionName = inputName.Substring(indx + 1); - } - } - else - { - host = parts[0]; - - if (parts.Length >= 2) - { - indx = parts[1].IndexOf('/'); - if(indx < 0) - { - // If it's a number then assume it's a port. Otherwise, it's a region name. - if (!UInt32.TryParse(parts[1], out port)) - { - port = 80; - regionName = parts[1]; - } - } - else - { - string portstr = parts[1].Substring(0, indx); - if(indx + 2 < parts[1].Length) - regionName = parts[1].Substring(indx + 1); - if (!UInt32.TryParse(portstr, out port)) - port = 80; - } - } - // always take the last one - if (parts.Length >= 3) - { - regionName = parts[2]; - } - - serverURI = "http://"+ host +":"+ port.ToString() + "/"; - } - } - else - { - // Formats: http://grid.example.com region name - // http://grid.example.com "region name" - // http://grid.example.com - - string[] parts = inputName.Split(new char[] { ' ' }); - - if (parts.Length == 0) - return false; - - serverURI = parts[0]; - - int indx = serverURI.LastIndexOf('/'); - if(indx > 10) - { - if(indx + 2 < inputName.Length) - regionName = inputName.Substring(indx + 1); - serverURI = inputName.Substring(0, indx + 1); - } - else if (parts.Length >= 2) - { - regionName = inputName.Substring(serverURI.Length); - } - } - - // use better code for sanity check - Uri uri; - try - { - uri = new Uri(serverURI); - } - catch - { - return false; - } - - if(!string.IsNullOrEmpty(regionName)) - regionName = regionName.Trim(new char[] { '"', ' ' }); - serverURI = uri.AbsoluteUri; - if(uri.Port == 80) - serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":80/"; - else if(uri.Port == 443) - serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":443/"; - - if(serverURI == m_ThisGatekeeper) - serverURI = ""; // local grid, look for region name only - - return true; + return serverURI == m_ThisGatekeeper; } public GridRegion TryLinkRegionToCoords(UUID scopeID, string mapName, int xloc, int yloc, UUID ownerID, out string reason) @@ -323,7 +210,7 @@ namespace OpenSim.Services.GridService string serverURI = string.Empty; string regionName = string.Empty; - if(!buildHGRegionURI(mapName, out serverURI, out regionName)) + if(!Util.buildHGRegionURI(mapName, out serverURI, out regionName)) { reason = "Wrong URI format for link-region"; return null; From 61d2fb6a17bc583678a383e1e640671432824ec7 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 16 Dec 2016 18:22:07 +0000 Subject: [PATCH 185/305] viewers regionhandle are not necessary region identifiers, compensate for that on GetLandData in case one get there --- .../ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs index b63214648c..1273f0d17f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs @@ -131,7 +131,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Land uint rx = 0, ry = 0; Util.RegionHandleToWorldLoc(regionHandle, out rx, out ry); - + rx += x; + ry += y; foreach (Scene s in m_Scenes) { uint t = s.RegionInfo.WorldLocX; @@ -147,6 +148,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Land if( ry < t) { // m_log.Debug("[LAND IN CONNECTOR]: Found region to GetLandData from"); + x = rx - s.RegionInfo.WorldLocX; + y = ry - s.RegionInfo.WorldLocY; regionAccess = s.RegionInfo.AccessLevel; return s.GetLandData(x, y); } From 1ddc90f16ea9e97a77b8f7c92567b03311fa293a Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 16 Dec 2016 18:55:13 +0000 Subject: [PATCH 186/305] useless change that doesn't fix anything --- .../Connectors/Land/LandServicesConnector.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/OpenSim/Services/Connectors/Land/LandServicesConnector.cs b/OpenSim/Services/Connectors/Land/LandServicesConnector.cs index 7839a68dcc..5e9331e3c4 100644 --- a/OpenSim/Services/Connectors/Land/LandServicesConnector.cs +++ b/OpenSim/Services/Connectors/Land/LandServicesConnector.cs @@ -66,22 +66,31 @@ namespace OpenSim.Services.Connectors public virtual LandData GetLandData(UUID scopeID, ulong regionHandle, uint x, uint y, out byte regionAccess) { LandData landData = null; - Hashtable hash = new Hashtable(); - hash["region_handle"] = regionHandle.ToString(); - hash["x"] = x.ToString(); - hash["y"] = y.ToString(); IList paramList = new ArrayList(); - paramList.Add(hash); regionAccess = 42; // Default to adult. Better safe... try { uint xpos = 0, ypos = 0; Util.RegionHandleToWorldLoc(regionHandle, out xpos, out ypos); + GridRegion info = m_GridService.GetRegionByPosition(scopeID, (int)xpos, (int)ypos); if (info != null) // just to be sure { + string targetHandlestr = info.RegionHandle.ToString(); + if( ypos == 0 ) //HG proxy? + { + // this is real region handle on hg proxies hack + targetHandlestr = info.RegionSecret; + } + + Hashtable hash = new Hashtable(); + hash["region_handle"] = targetHandlestr; + hash["x"] = x.ToString(); + hash["y"] = y.ToString(); + paramList.Add(hash); + XmlRpcRequest request = new XmlRpcRequest("land_data", paramList); XmlRpcResponse response = request.Send(info.ServerURI, 10000); if (response.IsFault) From be490a8312837ae66647a7597c29097a13d1c679 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 16 Dec 2016 19:11:05 +0000 Subject: [PATCH 187/305] remove a nonsense option --- OpenSim/Services/GridService/GridService.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index c51bb8b090..c5419d5cbc 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -57,9 +57,6 @@ namespace OpenSim.Services.GridService protected bool m_AllowDuplicateNames = false; protected bool m_AllowHypergridMapSearch = false; - - protected bool m_SuppressVarregionOverlapCheckOnRegistration = false; - private static Dictionary m_ExtraFeatures = new Dictionary(); public GridService(IConfigSource config) @@ -86,8 +83,6 @@ namespace OpenSim.Services.GridService m_AllowDuplicateNames = gridConfig.GetBoolean("AllowDuplicateNames", m_AllowDuplicateNames); m_AllowHypergridMapSearch = gridConfig.GetBoolean("AllowHypergridMapSearch", m_AllowHypergridMapSearch); - m_SuppressVarregionOverlapCheckOnRegistration = gridConfig.GetBoolean("SuppressVarregionOverlapCheckOnRegistration", m_SuppressVarregionOverlapCheckOnRegistration); - // This service is also used locally by a simulator running in grid mode. This switches prevents // inappropriate console commands from being registered suppressConsoleCommands = gridConfig.GetBoolean("SuppressConsoleCommands", suppressConsoleCommands); From 9b9f93c4b2f65e85129e50587a2ee63dd1d4f374 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 16 Dec 2016 20:31:07 +0000 Subject: [PATCH 188/305] and yes HG uri again --- OpenSim/Framework/Util.cs | 20 ++++++++++++ .../Grid/RemoteGridServiceConnector.cs | 32 +++++++++++++++---- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5d8a5e0142..b6225232db 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -414,6 +414,26 @@ namespace OpenSim.Framework return regionCoord << 8; } + public static bool checkServiceURI(string uristr, out string serviceURI) + { + serviceURI = string.Empty; + try + { + Uri uri = new Uri(uristr); + serviceURI = uri.AbsoluteUri; + if(uri.Port == 80) + serviceURI = serviceURI.Trim(new char[] { '/', ' ' }) +":80/"; + else if(uri.Port == 443) + serviceURI = serviceURI.Trim(new char[] { '/', ' ' }) +":443/"; + return true; + } + catch + { + serviceURI = string.Empty; + } + return false; + } + public static bool buildHGRegionURI(string inputName, out string serverURI, out string regionName) { serverURI = string.Empty; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs index f9ce5e1091..50e4c8a5ed 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs @@ -52,6 +52,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled = false; + private string m_ThisGatekeeper = string.Empty; private IGridService m_LocalGridService; private IGridService m_RemoteGridService; @@ -118,13 +119,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid m_LocalGridService = new LocalGridServicesConnector(source, m_RegionInfoCache); if (m_LocalGridService == null) { - m_log.Error("[REMOTE GRID CONNECTOR]: failed to loar local connector"); + m_log.Error("[REMOTE GRID CONNECTOR]: failed to load local connector"); return false; } if(m_RegionInfoCache == null) m_RegionInfoCache = new RegionInfoCache(); + m_ThisGatekeeper = Util.GetConfigVarFromSections(source, "GatekeeperURI", + new string[] { "Startup", "Hypergrid", "GridService" }, String.Empty); + // Legacy. Remove soon! + m_ThisGatekeeper = gridConfig.GetString("Gatekeeper", m_ThisGatekeeper); + + Util.checkServiceURI(m_ThisGatekeeper, out m_ThisGatekeeper); + return true; } @@ -233,13 +241,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid if (rinfo != null) return rinfo; - // HG urls should not get here, strip them + // HG urls should not get here, strip them + // side effect is that local regions with same name as HG may also be found + // this mb good or bad string regionName = name; if(name.Contains(".")) { + if(string.IsNullOrWhiteSpace(m_ThisGatekeeper)) + return rinfo; // no HG + string regionURI = ""; - if(!Util.buildHGRegionURI(name, out regionURI, out regionName)) - return rinfo; + if(!Util.buildHGRegionURI(name, out regionURI, out regionName) || string.IsNullOrWhiteSpace(regionName)) + return rinfo; // invalid + if(m_ThisGatekeeper != regionURI) + return rinfo; // not local grid } rinfo = m_RemoteGridService.GetRegionByName(scopeID, regionName); @@ -258,9 +273,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid string regionName = name; if(name.Contains(".")) { + if(string.IsNullOrWhiteSpace(m_ThisGatekeeper)) + return rinfo; // no HG + string regionURI = ""; - if(!Util.buildHGRegionURI(name, out regionURI, out regionName)) - return rinfo; + if(!Util.buildHGRegionURI(name, out regionURI, out regionName) || string.IsNullOrWhiteSpace(regionName)) + return rinfo; // invalid + if(m_ThisGatekeeper != regionURI) + return rinfo; // not local grid } List grinfo = m_RemoteGridService.GetRegionsByName(scopeID, regionName, maxNumber); From aa9a56d4df25c073c504575eee2dafcb3d08f6d1 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 16 Dec 2016 21:15:21 +0000 Subject: [PATCH 189/305] dont allow regions to be register on map area reserved for HG links --- OpenSim/Services/GridService/GridService.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index c5419d5cbc..aa13a677df 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -197,6 +197,9 @@ namespace OpenSim.Services.GridService if (regionInfos.RegionID == UUID.Zero) return "Invalid RegionID - cannot be zero UUID"; + if (regionInfos.RegionLocY <= Constants.MaximumRegionSize) + return "Region location reserved for HG links coord Y must be higher than " + (Constants.MaximumRegionSize/256).ToString(); + String reason = "Region overlaps another region"; List rdatas = m_Database.Get( @@ -290,7 +293,7 @@ namespace OpenSim.Services.GridService // Region reregistering in other coordinates. Delete the old entry m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) was previously registered at {2}-{3}. Deleting old entry.", - regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY); + regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY); try { From b4bbf4f95d1920af9b6e8dfb01ad66873cab9b8a Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 16 Dec 2016 23:28:14 +0000 Subject: [PATCH 190/305] review llCastRay V3 phantom detection. Make it ignore physics shape type none as physics engines do. --- .../Shared/Api/Implementation/LSL_Api.cs | 256 +++++++++--------- 1 file changed, 129 insertions(+), 127 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 7efdc62d43..eeaec42eff 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -15010,7 +15010,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api int rejectTypes = 0; int dataFlags = 0; int maxHits = 1; - bool detectPhantom = false; + bool notdetectPhantom = true; for (int i = 0; i < options.Length; i += 2) { if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) @@ -15020,7 +15020,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) maxHits = options.GetLSLIntegerItem(i + 1); else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) - detectPhantom = (options.GetLSLIntegerItem(i + 1) != 0); + notdetectPhantom = (options.GetLSLIntegerItem(i + 1) == 0); } if (maxHits > m_maxHitsInCastRay) maxHits = m_maxHitsInCastRay; @@ -15050,157 +15050,159 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.ForEachSOG( delegate(SceneObjectGroup group) { + if(group.IsDeleted || group.RootPart == null) + return; // Check group filters unless part filters are configured - bool isPhysical = (group.RootPart != null && group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical); + bool isPhysical = (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical); bool isNonphysical = !isPhysical; bool isPhantom = group.IsPhantom || group.IsVolumeDetect; bool isAttachment = group.IsAttachment; - bool doGroup = true; if (isPhysical && rejectPhysical) - doGroup = false; + return; if (isNonphysical && rejectNonphysical) - doGroup = false; - if (isPhantom && detectPhantom) - doGroup = true; + return; + if (isPhantom && notdetectPhantom) + return; if (m_filterPartsInCastRay) - doGroup = true; + return; if (isAttachment && !m_doAttachmentsInCastRay) - doGroup = false; + return; + // Parse object/group if passed filters - if (doGroup) + // Iterate over all prims/parts in object/group + foreach(SceneObjectPart part in group.Parts) { - // Iterate over all prims/parts in object/group - foreach(SceneObjectPart part in group.Parts) + // Check part filters if configured + if (m_filterPartsInCastRay) { - // Check part filters if configured - if (m_filterPartsInCastRay) + // ignore PhysicsShapeType.None as physics engines do + // or we will get into trouble in future + if(part.PhysicsShapeType == (byte)PhysicsShapeType.None) + continue; + isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical); + isNonphysical = !isPhysical; + isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || + (part.VolumeDetectActive); + + if (isPhysical && rejectPhysical) + continue; + if (isNonphysical && rejectNonphysical) + continue; + if (isPhantom && notdetectPhantom) + continue; + } + + // Parse prim/part and project ray if passed filters + Vector3 scalePart = part.Scale; + Vector3 posPart = part.GetWorldPosition(); + Quaternion rotPart = part.GetWorldRotation(); + Quaternion rotPartInv = Quaternion.Inverse(rotPart); + Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; + Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; + + // Filter parts by shape bounding boxes + Vector3 shapeBoxMax = new Vector3(0.5f, 0.5f, 0.5f); + if (!part.Shape.SculptEntry) + shapeBoxMax = shapeBoxMax * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); + shapeBoxMax = shapeBoxMax + (new Vector3(tol, tol, tol)); + if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) + { + // Prepare data needed to check for ray hits + RayTrans rayTrans = new RayTrans(); + rayTrans.PartId = part.UUID; + rayTrans.GroupId = part.ParentGroup.UUID; + rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; + rayTrans.ScalePart = scalePart; + rayTrans.PositionPart = posPart; + rayTrans.RotationPart = rotPart; + rayTrans.ShapeNeedsEnds = true; + rayTrans.Position1Ray = pos1Ray; + rayTrans.Position1RayProj = pos1RayProj; + rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; + + // Get detail level depending on type + int lod = 0; + // Mesh detail level + if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) + lod = (int)m_meshLodInCastRay; + // Sculpt detail level + else if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) + lod = (int)m_sculptLodInCastRay; + // Shape detail level + else if (!part.Shape.SculptEntry) + lod = (int)m_primLodInCastRay; + + // Try to get cached mesh if configured + ulong meshKey = 0; + FacetedMesh mesh = null; + if (m_useMeshCacheInCastRay) { - isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical); - isNonphysical = !isPhysical; - isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || (part.VolumeDetectActive); - bool doPart = true; - if (isPhysical && rejectPhysical) - doPart = false; - if (isNonphysical && rejectNonphysical) - doPart = false; - if (isPhantom && detectPhantom) - doPart = true; - if (!doPart) - continue; + meshKey = part.Shape.GetMeshKey(Vector3.One, (float)(4 << lod)); + lock (m_cachedMeshes) + { + m_cachedMeshes.TryGetValue(meshKey, out mesh); + } } - // Parse prim/part and project ray if passed filters - Vector3 scalePart = part.Scale; - Vector3 posPart = part.GetWorldPosition(); - Quaternion rotPart = part.GetWorldRotation(); - Quaternion rotPartInv = Quaternion.Inverse(rotPart); - Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; - Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; - - // Filter parts by shape bounding boxes - Vector3 shapeBoxMax = new Vector3(0.5f, 0.5f, 0.5f); - if (!part.Shape.SculptEntry) - shapeBoxMax = shapeBoxMax * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); - shapeBoxMax = shapeBoxMax + (new Vector3(tol, tol, tol)); - if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) + // Create mesh if no cached mesh + if (mesh == null) { - // Prepare data needed to check for ray hits - RayTrans rayTrans = new RayTrans(); - rayTrans.PartId = part.UUID; - rayTrans.GroupId = part.ParentGroup.UUID; - rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; - rayTrans.ScalePart = scalePart; - rayTrans.PositionPart = posPart; - rayTrans.RotationPart = rotPart; - rayTrans.ShapeNeedsEnds = true; - rayTrans.Position1Ray = pos1Ray; - rayTrans.Position1RayProj = pos1RayProj; - rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; + // Make an OMV prim to be able to mesh part + Primitive omvPrim = part.Shape.ToOmvPrimitive(posPart, rotPart); + byte[] sculptAsset = null; + if (omvPrim.Sculpt != null) + sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); - // Get detail level depending on type - int lod = 0; - // Mesh detail level - if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) - lod = (int)m_meshLodInCastRay; - // Sculpt detail level - else if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) - lod = (int)m_sculptLodInCastRay; - // Shape detail level - else if (!part.Shape.SculptEntry) - lod = (int)m_primLodInCastRay; - - // Try to get cached mesh if configured - ulong meshKey = 0; - FacetedMesh mesh = null; - if (m_useMeshCacheInCastRay) + // When part is mesh, get mesh + if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) { - meshKey = part.Shape.GetMeshKey(Vector3.One, (float)(4 << lod)); - lock (m_cachedMeshes) - { - m_cachedMeshes.TryGetValue(meshKey, out mesh); - } + AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); + FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, m_meshLodInCastRay, out mesh); + meshAsset = null; } - // Create mesh if no cached mesh - if (mesh == null) + // When part is sculpt, create mesh + // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. + else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) { - // Make an OMV prim to be able to mesh part - Primitive omvPrim = part.Shape.ToOmvPrimitive(posPart, rotPart); - byte[] sculptAsset = null; - if (omvPrim.Sculpt != null) - sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); - - // When part is mesh, get mesh - if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) + IJ2KDecoder imgDecoder = World.RequestModuleInterface(); + if (imgDecoder != null) { - AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); - FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, m_meshLodInCastRay, out mesh); - meshAsset = null; - } - - // When part is sculpt, create mesh - // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. - else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) - { - IJ2KDecoder imgDecoder = World.RequestModuleInterface(); - if (imgDecoder != null) + Image sculpt = imgDecoder.DecodeToImage(sculptAsset); + if (sculpt != null) { - Image sculpt = imgDecoder.DecodeToImage(sculptAsset); - if (sculpt != null) - { - mesh = primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, m_sculptLodInCastRay); - sculpt.Dispose(); - } - } - } - - // When part is shape, create mesh - else if (omvPrim.Sculpt == null) - { - if ( - omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 && - omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 && - omvPrim.PrimData.PathSkew == 0.0 && - omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 - ) - rayTrans.ShapeNeedsEnds = false; - mesh = primMesher.GenerateFacetedMesh(omvPrim, m_primLodInCastRay); - } - - // Cache mesh if configured - if (m_useMeshCacheInCastRay && mesh != null) - { - lock(m_cachedMeshes) - { - if (!m_cachedMeshes.ContainsKey(meshKey)) - m_cachedMeshes.Add(meshKey, mesh); + mesh = primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, m_sculptLodInCastRay); + sculpt.Dispose(); } } } - // Check mesh for ray hits - AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); - mesh = null; + + // When part is shape, create mesh + else if (omvPrim.Sculpt == null) + { + if ( + omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 && + omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 && + omvPrim.PrimData.PathSkew == 0.0 && + omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 + ) + rayTrans.ShapeNeedsEnds = false; + mesh = primMesher.GenerateFacetedMesh(omvPrim, m_primLodInCastRay); + } + + // Cache mesh if configured + if (m_useMeshCacheInCastRay && mesh != null) + { + lock(m_cachedMeshes) + { + if (!m_cachedMeshes.ContainsKey(meshKey)) + m_cachedMeshes.Add(meshKey, mesh); + } + } } + // Check mesh for ray hits + AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); + mesh = null; } } } From 389a1652fbd6827e8641b5dafe132cd4b5e849f9 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 17 Dec 2016 20:11:34 +0000 Subject: [PATCH 191/305] break userprofiles a bit more --- .../Avatar/UserProfiles/UserProfileModule.cs | 186 +++++++++++------- 1 file changed, 112 insertions(+), 74 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 1f7db64d98..57025bf3fc 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -161,7 +161,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } - m_allowUserProfileWebURLs = profileConfig.GetBoolean("AllowUserProfileWebURLs", m_allowUserProfileWebURLs); + m_allowUserProfileWebURLs = profileConfig.GetBoolean("AllowUserProfileWebURLs", m_allowUserProfileWebURLs); + m_log.Debug("[PROFILES]: Full Profiles Enabled"); ReplaceableInterface = null; Enabled = true; @@ -318,37 +319,46 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; IClientAPI remoteClient = (IClientAPI)sender; + Dictionary classifieds = new Dictionary(); UUID targetID; - UUID.TryParse(args[0], out targetID); - + if(!UUID.TryParse(args[0], out targetID) || targetID == UUID.Zero) + return; ScenePresence p = FindPresence(targetID); if (p != null && p.isNPC) { - remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), new Dictionary()); + remoteClient.SendAvatarClassifiedReply(targetID, classifieds); return; } string serverURI = string.Empty; GetUserProfileServerURI(targetID, out serverURI); - UUID creatorId = UUID.Zero; - Dictionary classifieds = new Dictionary(); + if(string.IsNullOrWhiteSpace(serverURI)) + { + remoteClient.SendAvatarClassifiedReply(targetID, classifieds); + return; + } OSDMap parameters= new OSDMap(); - UUID.TryParse(args[0], out creatorId); - parameters.Add("creatorId", OSD.FromUUID(creatorId)); + + parameters.Add("creatorId", OSD.FromUUID(targetID)); OSD Params = (OSD)parameters; if(!rpc.JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString())) { - remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds); + remoteClient.SendAvatarClassifiedReply(targetID, classifieds); return; } parameters = (OSDMap)Params; - OSDArray list = (OSDArray)parameters["result"]; + if(!parameters.ContainsKey("result") || parameters["result"] == null) + { + remoteClient.SendAvatarClassifiedReply(targetID, classifieds); + return; + } + OSDArray list = (OSDArray)parameters["result"]; foreach(OSD map in list) { @@ -362,7 +372,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if (!m_classifiedCache.ContainsKey(cid)) { - m_classifiedCache.Add(cid,creatorId); + m_classifiedCache.Add(cid,targetID); m_classifiedInterest.Add(cid, 0); } @@ -370,7 +380,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } - remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds); + remoteClient.SendAvatarClassifiedReply(targetID, classifieds); } public void ClassifiedInfoRequest(UUID queryClassifiedID, IClientAPI remoteClient) @@ -397,6 +407,10 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string serverURI = string.Empty; GetUserProfileServerURI(target, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + { + return; + } object Ad = (object)ad; if(!rpc.JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString())) @@ -467,6 +481,10 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + { + return; + } OSDMap parameters = new OSDMap {{"creatorId", OSD.FromUUID(creatorId)}}; OSD Params = (OSD)parameters; @@ -533,10 +551,14 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + return; UUID classifiedId; + if(!UUID.TryParse(queryClassifiedID.ToString(), out classifiedId)) + return; + OSDMap parameters= new OSDMap(); - UUID.TryParse(queryClassifiedID.ToString(), out classifiedId); parameters.Add("classifiedId", OSD.FromUUID(classifiedId)); OSD Params = (OSD)parameters; if(!rpc.JsonRpcRequest(ref Params, "classified_delete", serverURI, UUID.Random().ToString())) @@ -571,33 +593,41 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles IClientAPI remoteClient = (IClientAPI)sender; UUID targetId; - UUID.TryParse(args[0], out targetId); + if(!UUID.TryParse(args[0], out targetId)) + return; + + Dictionary picks = new Dictionary(); - // Can't handle NPC yet... ScenePresence p = FindPresence(targetId); - if (p != null && p.isNPC) { - remoteClient.SendAvatarPicksReply(new UUID(args[0]), new Dictionary()); + remoteClient.SendAvatarPicksReply(targetId, picks); return; } string serverURI = string.Empty; GetUserProfileServerURI(targetId, out serverURI); - - Dictionary picks = new Dictionary(); + if(string.IsNullOrWhiteSpace(serverURI)) + { + remoteClient.SendAvatarPicksReply(targetId, picks); + return; + } OSDMap parameters= new OSDMap(); parameters.Add("creatorId", OSD.FromUUID(targetId)); OSD Params = (OSD)parameters; if(!rpc.JsonRpcRequest(ref Params, "avatarpicksrequest", serverURI, UUID.Random().ToString())) { - remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks); + remoteClient.SendAvatarPicksReply(targetId, picks); return; } parameters = (OSDMap)Params; - + if(!parameters.ContainsKey("result") || parameters["result"] == null) + { + remoteClient.SendAvatarPicksReply(targetId, picks); + return; + } OSDArray list = (OSDArray)parameters["result"]; foreach(OSD map in list) @@ -605,12 +635,9 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles OSDMap m = (OSDMap)map; UUID cid = m["pickuuid"].AsUUID(); string name = m["name"].AsString(); - - m_log.DebugFormat("[PROFILES]: PicksRequest {0}", name); - picks[cid] = name; } - remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks); + remoteClient.SendAvatarPicksReply(targetId, picks); } /// @@ -630,20 +657,27 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (!(sender is IClientAPI)) return; + UserProfilePick pick = new UserProfilePick (); UUID targetID; - UUID.TryParse (args [0], out targetID); + if(!UUID.TryParse(args [0], out targetID)) + return; + + pick.CreatorId = targetID; + + if(!UUID.TryParse (args [1], out pick.PickId)) + return; + string serverURI = string.Empty; GetUserProfileServerURI (targetID, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + { + return; + } string theirGatekeeperURI; - GetUserGatekeeperURI (targetID, out theirGatekeeperURI); + GetUserGatekeeperURI(targetID, out theirGatekeeperURI); IClientAPI remoteClient = (IClientAPI)sender; - - UserProfilePick pick = new UserProfilePick (); - UUID.TryParse (args [0], out pick.CreatorId); - UUID.TryParse (args [1], out pick.PickId); - object Pick = (object)pick; if (!rpc.JsonRpcRequest (ref Pick, "pickinforequest", serverURI, UUID.Random ().ToString ())) { @@ -654,13 +688,9 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles pick = (UserProfilePick)Pick; Vector3 globalPos = new Vector3(Vector3.Zero); + Vector3.TryParse(pick.GlobalPos, out globalPos); - // Smoke and mirrors - if (pick.Gatekeeper == MyGatekeeper) - { - Vector3.TryParse(pick.GlobalPos,out globalPos); - } - else + if (!string.IsNullOrWhiteSpace(MyGatekeeper) && pick.Gatekeeper != MyGatekeeper) { // Setup the illusion string region = string.Format("{0} {1}",pick.Gatekeeper,pick.SimName); @@ -668,21 +698,19 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(target == null) { - // This is a dead or unreachable region + // This is a unreachable region } else { - // Work our slight of hand - int x = target.RegionLocX; - int y = target.RegionLocY; + // we have a proxy on map + // this is a fail on large regions + uint gtmp = (uint)globalPos.X >> 8; + globalPos.X -= (gtmp << 8); + globalPos.X += target.RegionLocX; - dynamic synthX = globalPos.X - (globalPos.X/Constants.RegionSize) * Constants.RegionSize; - synthX += x; - globalPos.X = synthX; - - dynamic synthY = globalPos.Y - (globalPos.Y/Constants.RegionSize) * Constants.RegionSize; - synthY += y; - globalPos.Y = synthY; + gtmp = (uint)globalPos.Y >> 8; + globalPos.Y -= (gtmp << 8); + globalPos.Y += target.RegionLocY; } } @@ -732,6 +760,11 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles UserProfilePick pick = new UserProfilePick(); string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + { + return; + } + ScenePresence p = FindPresence(remoteClient.AgentId); Vector3 avaPos = p.AbsolutePosition; @@ -797,6 +830,10 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + { + return; + } OSDMap parameters= new OSDMap(); parameters.Add("pickId", OSD.FromUUID(queryPickID)); @@ -830,11 +867,19 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (!(sender is IClientAPI)) return; + if(!UUID.TryParse(args[0], out note.TargetId)) + return; + IClientAPI remoteClient = (IClientAPI)sender; + note.UserId = remoteClient.AgentId; + string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); - note.UserId = remoteClient.AgentId; - UUID.TryParse(args[0], out note.TargetId); + if(string.IsNullOrWhiteSpace(serverURI)) + { + remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes); + return; + } object Note = (object)note; if(!rpc.JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString())) @@ -842,8 +887,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes); return; } - note = (UserProfileNotes) Note; - + note = (UserProfileNotes) Note; remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes); } @@ -877,6 +921,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + return; object Note = note; if(!rpc.JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString())) @@ -912,6 +958,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string serverURI = string.Empty; bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + return; object Pref = pref; if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_update", serverURI, UUID.Random().ToString())) @@ -936,7 +984,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string serverURI = string.Empty; bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); - + if(string.IsNullOrWhiteSpace(serverURI)) + return; object Pref = (object)pref; if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_request", serverURI, UUID.Random().ToString())) @@ -987,6 +1036,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + return; object Param = prop; if(!rpc.JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString())) @@ -1006,9 +1057,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } - // Can't handle NPC yet... ScenePresence p = FindPresence(avatarID); - if (p != null && p.isNPC) { remoteClient.SendAvatarProperties(avatarID, ((INPC)(p.ControllingClient)).profileAbout, ((INPC)(p.ControllingClient)).Born, @@ -1035,19 +1084,15 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } Byte[] membershipType = new Byte[1]; - string born = String.Empty; + string born = string.Empty; uint flags = 0x00; if (null != account) { if (account.UserTitle == "") - { membershipType[0] = (Byte)((account.UserFlags & 0xf00) >> 8); - } else - { membershipType = Utils.StringToBytes(account.UserTitle); - } born = Util.ToDateTime(account.Created).ToString( "M/d/yyyy", CultureInfo.InvariantCulture); @@ -1058,16 +1103,13 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (GetUserAccountData(avatarID, out userInfo) == true) { if ((string)userInfo["user_title"] == "") - { membershipType[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8); - } else - { membershipType = Utils.StringToBytes((string)userInfo["user_title"]); - } int val_born = (int)userInfo["user_created"]; - born = Util.ToDateTime(val_born).ToString( + if(val_born != 0) + born = Util.ToDateTime(val_born).ToString( "M/d/yyyy", CultureInfo.InvariantCulture); // picky, picky @@ -1077,20 +1119,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } UserProfileProperties props = new UserProfileProperties(); - string result = string.Empty; - props.UserId = avatarID; - if (!GetProfileData(ref props, foreign, out result)) + string result = string.Empty; + if(!GetProfileData(ref props, foreign, out result)) { -// m_log.DebugFormat("Error getting profile for {0}: {1}", avatarID, result); - return; + props.AboutText ="Profile not avaible at this time. User may still be unknown to this grid"; } // if on same region force online if(p != null && !p.IsDeleted) flags |= 0x10; - if(!m_allowUserProfileWebURLs) props.WebUrl =""; @@ -1166,12 +1205,11 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string serverURI = string.Empty; GetUserProfileServerURI(properties.UserId, out serverURI); - // This is checking a friend on the home grid // Not HG friend if (String.IsNullOrEmpty(serverURI)) { - message = "No Presence - foreign friend"; + message = "User profile service unknown at this time"; return false; } From c93551d8f43cf91f909a3909bc2bdbf70666201b Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 17 Dec 2016 22:38:31 +0000 Subject: [PATCH 192/305] allow a creator that is also onwer to change export flag. Add missing setting to ini files --- .../Region/Framework/Scenes/Scene.Inventory.cs | 6 ++++-- bin/OpenSim.ini.example | 4 ++++ bin/OpenSimDefaults.ini | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 61ea8acd0f..000944f5da 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -431,9 +431,11 @@ namespace OpenSim.Region.Framework.Scenes bool denyExportChange = false; // m_log.DebugFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions); - + const uint permALLandExport = (uint)(PermissionMask.All | PermissionMask.Export); // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export - if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner) + if (item.CreatorIdAsUuid != item.Owner && + ((item.BasePermissions & permALLandExport) != permALLandExport || + (item.CurrentPermissions & (uint)PermissionMask.Export) == 0)) denyExportChange = true; // m_log.DebugFormat("[XXX]: Deny Export Update {0}", denyExportChange); diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 5f1e779337..41bb26350e 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -619,6 +619,10 @@ ;; supported by viewers. ;DestinationGuideURI = "http://127.0.0.1:9000/guide" + ;# {ExportSupported} {} {Enable export control flag} {true false} false + ;; set to true to allow the export control flag of items + ; ExportSupported = false + [Chat] ;# {whisper_distance} {} {Distance at which a whisper is heard, in meters?} {} 10 diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index b133da9343..423d8dc362 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -836,6 +836,21 @@ ; Capability for searching for people Cap_AvatarPickerSearch = "localhost" +[SimulatorFeatures] + ;# {SearchServerURI} {} {URL of the search server} {} + ;; Optional. If given this serves the same purpose as the grid wide + ;; [LoginServices] SearchURL setting and will override that where + ;; supported by viewers. + ;SearchServerURI = "http://127.0.0.1:9000/" + + ;# {DestinationGuideURI} {} {URL of the destination guide} {} + ;; Optional. If given this serves the same purpose as the grid wide + ;; [LoginServices] DestinationGuide setting and will override that where + ;; supported by viewers. + ;DestinationGuideURI = "http://127.0.0.1:9000/guide" + + ; set to true to allow the export control flag of items + ; ExportSupported = false [Chat] ; Controls whether the chat module is enabled. Default is true. From df7435a7030bc88987f2a60a2fe118f13342a31c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 18 Dec 2016 03:20:41 +0000 Subject: [PATCH 193/305] just give up on Export flag, seems just broken no matter water with current FS and singu 1.8.7 --- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 5 ++++- .../Region/Framework/Scenes/SceneObjectGroup.Inventory.cs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 000944f5da..9772b352d5 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -433,7 +433,7 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions); const uint permALLandExport = (uint)(PermissionMask.All | PermissionMask.Export); // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export - if (item.CreatorIdAsUuid != item.Owner && + if (item.CreatorIdAsUuid != item.Owner || ((item.BasePermissions & permALLandExport) != permALLandExport || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0)) denyExportChange = true; @@ -451,10 +451,12 @@ namespace OpenSim.Region.Framework.Scenes { itemUpd.NextPermissions = (uint)(PermissionMask.All); itemUpd.EveryOnePermissions |= (uint)PermissionMask.Export; + sendUpdate = true; } else { itemUpd.EveryOnePermissions &= ~(uint)PermissionMask.Export; + sendUpdate = true; } } else @@ -464,6 +466,7 @@ namespace OpenSim.Region.Framework.Scenes { // m_log.DebugFormat("[XXX]: Force full perm"); itemUpd.NextPermissions = (uint)(PermissionMask.All); + sendUpdate = true; } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index 98617d196b..68d80f0926 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs @@ -258,7 +258,8 @@ namespace OpenSim.Region.Framework.Scenes uint perms=(uint)(PermissionMask.Modify | PermissionMask.Copy | PermissionMask.Move | - PermissionMask.Transfer) | 7; + PermissionMask.Transfer | + PermissionMask.Export ) | 7; uint ownerMask = 0x7fffffff; @@ -281,6 +282,8 @@ namespace OpenSim.Region.Framework.Scenes perms &= ~(uint)PermissionMask.Copy; if ((ownerMask & (uint)PermissionMask.Transfer) == 0) perms &= ~(uint)PermissionMask.Transfer; + if ((ownerMask & (uint)PermissionMask.Export) == 0) + perms &= ~(uint)PermissionMask.Export; // If root prim permissions are applied here, this would screw // with in-inventory manipulation of the next owner perms From 2cf422582aad3dc99304b831b7d8bece2b28ecb3 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 18 Dec 2016 03:55:44 +0000 Subject: [PATCH 194/305] leave stupid broken permissions alone --- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 5 +---- .../Region/Framework/Scenes/SceneObjectGroup.Inventory.cs | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 9772b352d5..000944f5da 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -433,7 +433,7 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions); const uint permALLandExport = (uint)(PermissionMask.All | PermissionMask.Export); // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export - if (item.CreatorIdAsUuid != item.Owner || + if (item.CreatorIdAsUuid != item.Owner && ((item.BasePermissions & permALLandExport) != permALLandExport || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0)) denyExportChange = true; @@ -451,12 +451,10 @@ namespace OpenSim.Region.Framework.Scenes { itemUpd.NextPermissions = (uint)(PermissionMask.All); itemUpd.EveryOnePermissions |= (uint)PermissionMask.Export; - sendUpdate = true; } else { itemUpd.EveryOnePermissions &= ~(uint)PermissionMask.Export; - sendUpdate = true; } } else @@ -466,7 +464,6 @@ namespace OpenSim.Region.Framework.Scenes { // m_log.DebugFormat("[XXX]: Force full perm"); itemUpd.NextPermissions = (uint)(PermissionMask.All); - sendUpdate = true; } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index 68d80f0926..98617d196b 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs @@ -258,8 +258,7 @@ namespace OpenSim.Region.Framework.Scenes uint perms=(uint)(PermissionMask.Modify | PermissionMask.Copy | PermissionMask.Move | - PermissionMask.Transfer | - PermissionMask.Export ) | 7; + PermissionMask.Transfer) | 7; uint ownerMask = 0x7fffffff; @@ -282,8 +281,6 @@ namespace OpenSim.Region.Framework.Scenes perms &= ~(uint)PermissionMask.Copy; if ((ownerMask & (uint)PermissionMask.Transfer) == 0) perms &= ~(uint)PermissionMask.Transfer; - if ((ownerMask & (uint)PermissionMask.Export) == 0) - perms &= ~(uint)PermissionMask.Export; // If root prim permissions are applied here, this would screw // with in-inventory manipulation of the next owner perms From 30cd36ff98e9f695ec2aa3e7bf3a558dc19897db Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 18 Dec 2016 03:56:53 +0000 Subject: [PATCH 195/305] leave stupid broken permissions alone --- .../Region/Framework/Scenes/Scene.Inventory.cs | 6 ++---- bin/OpenSim.ini.example | 4 ---- bin/OpenSimDefaults.ini | 15 --------------- 3 files changed, 2 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 000944f5da..61ea8acd0f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -431,11 +431,9 @@ namespace OpenSim.Region.Framework.Scenes bool denyExportChange = false; // m_log.DebugFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions); - const uint permALLandExport = (uint)(PermissionMask.All | PermissionMask.Export); + // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export - if (item.CreatorIdAsUuid != item.Owner && - ((item.BasePermissions & permALLandExport) != permALLandExport || - (item.CurrentPermissions & (uint)PermissionMask.Export) == 0)) + if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner) denyExportChange = true; // m_log.DebugFormat("[XXX]: Deny Export Update {0}", denyExportChange); diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 41bb26350e..5f1e779337 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -619,10 +619,6 @@ ;; supported by viewers. ;DestinationGuideURI = "http://127.0.0.1:9000/guide" - ;# {ExportSupported} {} {Enable export control flag} {true false} false - ;; set to true to allow the export control flag of items - ; ExportSupported = false - [Chat] ;# {whisper_distance} {} {Distance at which a whisper is heard, in meters?} {} 10 diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 423d8dc362..b133da9343 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -836,21 +836,6 @@ ; Capability for searching for people Cap_AvatarPickerSearch = "localhost" -[SimulatorFeatures] - ;# {SearchServerURI} {} {URL of the search server} {} - ;; Optional. If given this serves the same purpose as the grid wide - ;; [LoginServices] SearchURL setting and will override that where - ;; supported by viewers. - ;SearchServerURI = "http://127.0.0.1:9000/" - - ;# {DestinationGuideURI} {} {URL of the destination guide} {} - ;; Optional. If given this serves the same purpose as the grid wide - ;; [LoginServices] DestinationGuide setting and will override that where - ;; supported by viewers. - ;DestinationGuideURI = "http://127.0.0.1:9000/guide" - - ; set to true to allow the export control flag of items - ; ExportSupported = false [Chat] ; Controls whether the chat module is enabled. Default is true. From eabd8cbe48b2b4af3fc9c04b695f4d5ebe561fcb Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 18 Dec 2016 07:11:20 +0000 Subject: [PATCH 196/305] a few updates to contributors list (sorry the ones still missing) --- CONTRIBUTORS.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index db2f16bfb5..d540c07d76 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -89,6 +89,7 @@ what it is today. * dmiles (Daxtron Labs) * Dong Jun Lan (IBM) * DoranZemlja +* Drake Arconis * dr0b3rts * dslake * eeyore @@ -107,6 +108,7 @@ what it is today. * Flyte Xevious * Freaky Tech * Garmin Kawaguichi +* Geir Noklebye * Glenn Martin (MOSES) * Gryc Ueusp * H-H-H (ginge264) @@ -115,6 +117,7 @@ what it is today. * Imaze Rhiano * Intimidated * Jak Daniels +* Jeff Kelly * Jeremy Bongio (IBM) * jhurliman * John R Sohn (XenReborn) @@ -136,6 +139,7 @@ what it is today. * Magnuz Binder * maimedleech * Mana Janus +* Mandarinka Tasty * MarcelEdward * Matt Lehmann * Mic Bowman @@ -158,6 +162,7 @@ what it is today. * openlifegrid.com * otakup0pe * Pixel Tomsen +* Quill Littlefeather * ralphos * RemedyTomm * Revolution @@ -183,6 +188,7 @@ what it is today. * TBG Renfold * tglion * tlaukkan/Tommil (Tommi S. E. Laukkanen, Bubble Cloud) +* TomDataWorks * TomTheDragon (muckwaddle) * tyre * Vegaslon From e40820cab16500c6aac2aa25d1ea0cdc6725c392 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Tue, 20 Dec 2016 17:01:48 +0000 Subject: [PATCH 197/305] Remove obsolete "gridmode" config default in code. --- OpenSim/Tools/Configger/ConfigurationLoader.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenSim/Tools/Configger/ConfigurationLoader.cs b/OpenSim/Tools/Configger/ConfigurationLoader.cs index 4190f107a4..31ae923518 100644 --- a/OpenSim/Tools/Configger/ConfigurationLoader.cs +++ b/OpenSim/Tools/Configger/ConfigurationLoader.cs @@ -264,7 +264,6 @@ namespace OpenSim.Tools.Configger config.Set("region_info_source", "filesystem"); config.Set("allow_regionless", false); - config.Set("gridmode", false); config.Set("physics", "OpenDynamicsEngine"); config.Set("meshing", "Meshmerizer"); config.Set("physical_prim", true); @@ -281,4 +280,4 @@ namespace OpenSim.Tools.Configger return defaultConfig; } } -} \ No newline at end of file +} From 66c18438f21737d2ea6dc3af726bc8950506e2e8 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Tue, 20 Dec 2016 17:08:15 +0000 Subject: [PATCH 198/305] remove obsolete config option "storage_prim_inventories" --- OpenSim/Region/Application/ConfigurationLoader.cs | 3 +-- OpenSim/Tools/Configger/ConfigurationLoader.cs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs index b19e5491c7..522fe0ec98 100644 --- a/OpenSim/Region/Application/ConfigurationLoader.cs +++ b/OpenSim/Region/Application/ConfigurationLoader.cs @@ -348,7 +348,6 @@ namespace OpenSim config.Set("meshing", "Meshmerizer"); config.Set("physical_prim", true); config.Set("serverside_object_permissions", true); - config.Set("storage_prim_inventories", true); config.Set("startup_console_commands_file", String.Empty); config.Set("shutdown_console_commands_file", String.Empty); config.Set("DefaultScriptEngine", "XEngine"); @@ -387,4 +386,4 @@ namespace OpenSim m_networkServersInfo.loadFromConfiguration(m_config.Source); } } -} \ No newline at end of file +} diff --git a/OpenSim/Tools/Configger/ConfigurationLoader.cs b/OpenSim/Tools/Configger/ConfigurationLoader.cs index 31ae923518..aba7e64e55 100644 --- a/OpenSim/Tools/Configger/ConfigurationLoader.cs +++ b/OpenSim/Tools/Configger/ConfigurationLoader.cs @@ -268,7 +268,6 @@ namespace OpenSim.Tools.Configger config.Set("meshing", "Meshmerizer"); config.Set("physical_prim", true); config.Set("serverside_object_permissions", true); - config.Set("storage_prim_inventories", true); config.Set("startup_console_commands_file", String.Empty); config.Set("shutdown_console_commands_file", String.Empty); config.Set("DefaultScriptEngine", "XEngine"); From 90be8d78c31d583eedd591f6c569efc38960e1dc Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Tue, 20 Dec 2016 17:10:33 +0000 Subject: [PATCH 199/305] Remove obsolete config option "EventQueue". It's been always on for ages! --- OpenSim/Region/Application/ConfigurationLoader.cs | 2 -- .../Linden/Caps/EventQueue/Tests/EventQueueTests.cs | 3 +-- .../Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs | 1 - OpenSim/Tools/Configger/ConfigurationLoader.cs | 2 -- 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs index 522fe0ec98..4f141a6e70 100644 --- a/OpenSim/Region/Application/ConfigurationLoader.cs +++ b/OpenSim/Region/Application/ConfigurationLoader.cs @@ -352,8 +352,6 @@ namespace OpenSim config.Set("shutdown_console_commands_file", String.Empty); config.Set("DefaultScriptEngine", "XEngine"); config.Set("clientstack_plugin", "OpenSim.Region.ClientStack.LindenUDP.dll"); - // life doesn't really work without this - config.Set("EventQueue", true); } { diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index 5eb44520b9..1e629bd577 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs @@ -71,7 +71,6 @@ namespace OpenSim.Region.ClientStack.Linden.Tests IConfigSource config = new IniConfigSource(); config.AddConfig("Startup"); - config.Configs["Startup"].Set("EventQueue", "true"); CapabilitiesModule capsModule = new CapabilitiesModule(); m_eqgMod = new EventQueueGetModule(); @@ -196,4 +195,4 @@ namespace OpenSim.Region.ClientStack.Linden.Tests Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway)); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs index 568cd34205..ada407f2c9 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs @@ -271,7 +271,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests IConfigSource configSource = new IniConfigSource(); IConfig config = configSource.AddConfig("Startup"); config.Set("serverside_object_permissions", true); - config.Set("EventQueue", true); EntityTransferModule etm = new EntityTransferModule(); diff --git a/OpenSim/Tools/Configger/ConfigurationLoader.cs b/OpenSim/Tools/Configger/ConfigurationLoader.cs index aba7e64e55..fa3a5bf11a 100644 --- a/OpenSim/Tools/Configger/ConfigurationLoader.cs +++ b/OpenSim/Tools/Configger/ConfigurationLoader.cs @@ -272,8 +272,6 @@ namespace OpenSim.Tools.Configger config.Set("shutdown_console_commands_file", String.Empty); config.Set("DefaultScriptEngine", "XEngine"); config.Set("clientstack_plugin", "OpenSim.Region.ClientStack.LindenUDP.dll"); - // life doesn't really work without this - config.Set("EventQueue", true); } return defaultConfig; From 7286b27ff93f566596310fc16e46d95abfa3502e Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Wed, 21 Dec 2016 14:35:34 +0000 Subject: [PATCH 200/305] Add GRID_GOD to the list of values allowed for enabling OSSL functions --- .../Shared/Api/Implementation/OSSL_Api.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index c83682ece5..c6a4050197 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -310,7 +310,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (string id in ids) { string current = id.Trim(); - if (current.ToUpper() == "PARCEL_GROUP_MEMBER" || current.ToUpper() == "PARCEL_OWNER" || current.ToUpper() == "ESTATE_MANAGER" || current.ToUpper() == "ESTATE_OWNER") + if (current.ToUpper() == "PARCEL_GROUP_MEMBER" || current.ToUpper() == "PARCEL_OWNER" || current.ToUpper() == "ESTATE_MANAGER" || current.ToUpper() == "ESTATE_OWNER" || current.ToUpper() == "GRID_GOD") { if (!perms.AllowedOwnerClasses.Contains(current)) perms.AllowedOwnerClasses.Add(current.ToUpper()); @@ -415,6 +415,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + //Only gods may use the function + if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("GRID_GOD")) + { + if (World.Permissions.IsAdministrator(ownerID)) + { + return String.Empty; + } + } + if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID)) return( String.Format("{0} permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission.", From 7367f03d6e990983c9ff6e3f5da11a1fe804b632 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 21 Dec 2016 20:39:38 +0000 Subject: [PATCH 201/305] remove a odd raycastv3 config option --- .../Shared/Api/Implementation/LSL_Api.cs | 36 ++++++++----------- bin/OpenSimDefaults.ini | 3 -- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index eeaec42eff..5269bf91b1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -233,7 +233,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected int m_maxHitsPerPrimInCastRay = 16; protected int m_maxHitsPerObjectInCastRay = 16; protected bool m_detectExitsInCastRay = false; - protected bool m_filterPartsInCastRay = false; protected bool m_doAttachmentsInCastRay = false; protected int m_msThrottleInCastRay = 200; protected int m_msPerRegionInCastRay = 40; @@ -391,7 +390,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay); m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay); m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay); - m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay); m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay); m_msThrottleInCastRay = lslConfig.GetInt("ThrottleTimeInMsInLlCastRay", m_msThrottleInCastRay); m_msPerRegionInCastRay = lslConfig.GetInt("AvailableTimeInMsPerRegionInLlCastRay", m_msPerRegionInCastRay); @@ -15063,8 +15061,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; if (isPhantom && notdetectPhantom) return; - if (m_filterPartsInCastRay) - return; if (isAttachment && !m_doAttachmentsInCastRay) return; @@ -15072,25 +15068,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Iterate over all prims/parts in object/group foreach(SceneObjectPart part in group.Parts) { - // Check part filters if configured - if (m_filterPartsInCastRay) - { - // ignore PhysicsShapeType.None as physics engines do - // or we will get into trouble in future - if(part.PhysicsShapeType == (byte)PhysicsShapeType.None) - continue; - isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical); - isNonphysical = !isPhysical; - isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || - (part.VolumeDetectActive); + // ignore PhysicsShapeType.None as physics engines do + // or we will get into trouble in future + if(part.PhysicsShapeType == (byte)PhysicsShapeType.None) + continue; + isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical); + isNonphysical = !isPhysical; + isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || + (part.VolumeDetectActive); - if (isPhysical && rejectPhysical) - continue; - if (isNonphysical && rejectNonphysical) - continue; - if (isPhantom && notdetectPhantom) - continue; - } + if (isPhysical && rejectPhysical) + continue; + if (isNonphysical && rejectNonphysical) + continue; + if (isPhantom && notdetectPhantom) + continue; // Parse prim/part and project ray if passed filters Vector3 scalePart = part.Scale; diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index b133da9343..644391fe36 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1635,9 +1635,6 @@ ; Report ray intersections with surfaces on exits from a prim as hits in llCastRay V3 if true DetectExitHitsInLlCastRay = false - ; Filter on parts instead of groups in llCastRay V3 if true - FilterPartsInLlCastRay = false - ; Detect attachments in llCastRay V3 if true DoAttachmentsInLlCastRay = false From 2bfbd6ef2e2628d130f5c8ba502f2247d074ce55 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Wed, 21 Dec 2016 20:56:28 +0000 Subject: [PATCH 202/305] Change GRID_GOD script permission to do what it says on the tin. Suggested by Mandarinka --- .../Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index c6a4050197..5638f01cba 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -418,7 +418,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api //Only gods may use the function if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("GRID_GOD")) { - if (World.Permissions.IsAdministrator(ownerID)) + if (World.Permissions.IsGridGod(ownerID)) { return String.Empty; } From 330369f90445bf7a017d25bbf8de647db9621f25 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 21 Dec 2016 22:27:48 +0000 Subject: [PATCH 203/305] take UserProfileModule out on onMakeRoot event, add some caching --- OpenSim/Framework/UserProfiles.cs | 14 + .../Avatar/UserProfiles/UserProfileModule.cs | 387 ++++++++++++++---- 2 files changed, 310 insertions(+), 91 deletions(-) diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs index 98ab651324..6d46fe9c2d 100644 --- a/OpenSim/Framework/UserProfiles.cs +++ b/OpenSim/Framework/UserProfiles.cs @@ -27,6 +27,8 @@ using System; using OpenMetaverse; +using System.Collections.Generic; + namespace OpenSim.Framework { @@ -122,5 +124,17 @@ namespace OpenSim.Framework public string UserId = UUID.Zero.ToString(); public string DataVal = string.Empty; } + + public class UserProfileCacheEntry + { + public Dictionary picksList; + public Dictionary picks; + public Dictionary classifiedsLists; + public Dictionary classifieds; + public UserProfileProperties props; + public string born; + public byte[] membershipType; + public uint flags; + } } diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 57025bf3fc..3890bb294c 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -57,6 +57,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserProfilesModule")] public class UserProfileModule : IProfileModule, INonSharedRegionModule { + const double PROFILECACHEEXPIRE = 300; /// /// Logging /// @@ -67,6 +68,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles // count. The entries are removed when the interest count reaches 0. Dictionary m_classifiedCache = new Dictionary(); Dictionary m_classifiedInterest = new Dictionary(); + ExpiringCache m_profilesCache = new ExpiringCache(); + IImprovedAssetCache m_assetCache; private JsonRpcRequestManager rpc = new JsonRpcRequestManager(); private bool m_allowUserProfileWebURLs = true; @@ -128,7 +131,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles get; private set; } - #region IRegionModuleBase implementation /// /// This is called to initialize the region module. For shared modules, this is called exactly once, after @@ -185,22 +187,11 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles Scene = scene; Scene.RegisterModuleInterface(this); Scene.EventManager.OnNewClient += OnNewClient; - Scene.EventManager.OnMakeRootAgent += HandleOnMakeRootAgent; + Scene.EventManager.OnClientClosed += OnClientClosed; UserManagementModule = Scene.RequestModuleInterface(); } - void HandleOnMakeRootAgent (ScenePresence obj) - { - if(obj.PresenceType == PresenceType.Npc) - return; - - Util.FireAndForget(delegate - { - GetImageAssets(((IScenePresence)obj).UUID); - }, null, "UserProfileModule.GetImageAssets"); - } - /// /// Removes the region. /// @@ -211,6 +202,10 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if(!Enabled) return; + + m_profilesCache.Clear(); + m_classifiedCache.Clear(); + m_classifiedInterest.Clear(); } /// @@ -226,6 +221,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if(!Enabled) return; + m_assetCache = Scene.RequestModuleInterface(); } /// @@ -297,6 +293,40 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles client.OnUserInfoRequest += UserPreferencesRequest; client.OnUpdateUserInfo += UpdateUserPreferences; } + + void OnClientClosed(UUID AgentId, Scene scene) + { + ScenePresence sp = scene.GetScenePresence(AgentId); + IClientAPI client = sp.ControllingClient; + if (client == null) + return; + + //Profile + client.OnRequestAvatarProperties -= RequestAvatarProperties; + client.OnUpdateAvatarProperties -= AvatarPropertiesUpdate; + client.OnAvatarInterestUpdate -= AvatarInterestsUpdate; + + // Classifieds +// client.r GenericPacketHandler("avatarclassifiedsrequest", ClassifiedsRequest); + client.OnClassifiedInfoUpdate -= ClassifiedInfoUpdate; + client.OnClassifiedInfoRequest -= ClassifiedInfoRequest; + client.OnClassifiedDelete -= ClassifiedDelete; + + // Picks +// client.AddGenericPacketHandler("avatarpicksrequest", PicksRequest); +// client.AddGenericPacketHandler("pickinforequest", PickInfoRequest); + client.OnPickInfoUpdate -= PickInfoUpdate; + client.OnPickDelete -= PickDelete; + + // Notes +// client.AddGenericPacketHandler("avatarnotesrequest", NotesRequest); + client.OnAvatarNotesUpdate -= NotesUpdate; + + // Preferences + client.OnUserInfoRequest -= UserPreferencesRequest; + client.OnUpdateUserInfo -= UpdateUserPreferences; + } + #endregion Region Event Handlers #region Classified @@ -332,6 +362,34 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(targetID, out uce) && uce != null) + { + if(uce.classifiedsLists != null) + { + foreach(KeyValuePair kvp in uce.classifiedsLists) + { + UUID kvpkey = kvp.Key; + classifieds[kvpkey] = kvp.Value; + lock (m_classifiedCache) + { + if (!m_classifiedCache.ContainsKey(kvpkey)) + { + m_classifiedCache.Add(kvpkey,targetID); + m_classifiedInterest.Add(kvpkey, 0); + } + + m_classifiedInterest[kvpkey]++; + } + } + remoteClient.SendAvatarClassifiedReply(targetID, uce.classifiedsLists); + return; + } + } + } + string serverURI = string.Empty; GetUserProfileServerURI(targetID, out serverURI); if(string.IsNullOrWhiteSpace(serverURI)) @@ -380,6 +438,13 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } + if(uce == null) + uce = new UserProfileCacheEntry(); + uce.classifiedsLists = classifieds; + + lock(m_profilesCache) + m_profilesCache.AddOrUpdate(targetID, uce, PROFILECACHEEXPIRE); + remoteClient.SendAvatarClassifiedReply(targetID, classifieds); } @@ -404,9 +469,29 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } } - + + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(target, out uce) && uce != null) + { + if(uce.classifieds != null && uce.classifieds.ContainsKey(queryClassifiedID)) + { + ad = uce.classifieds[queryClassifiedID]; + Vector3 gPos = new Vector3(); + Vector3.TryParse(ad.GlobalPos, out gPos); + + remoteClient.SendClassifiedInfoReply(ad.ClassifiedId, ad.CreatorId, (uint)ad.CreationDate, + (uint)ad.ExpirationDate, (uint)ad.Category, ad.Name, ad.Description, + ad.ParcelId, (uint)ad.ParentEstate, ad.SnapshotId, ad.SimName, + gPos, ad.ParcelName, ad.Flags, ad.Price); + return; + } + } + } + string serverURI = string.Empty; - GetUserProfileServerURI(target, out serverURI); + bool foreign = GetUserProfileServerURI(target, out serverURI); if(string.IsNullOrWhiteSpace(serverURI)) { return; @@ -424,6 +509,18 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(ad.CreatorId == UUID.Zero) return; + if(foreign) + cacheForeignImage(target, ad.SnapshotId); + + if(uce == null) + uce = new UserProfileCacheEntry(); + if(uce.classifieds == null) + uce.classifieds = new Dictionary(); + uce.classifieds[ad.ClassifiedId] = ad; + + lock(m_profilesCache) + m_profilesCache.AddOrUpdate(ad.ClassifiedId, uce, PROFILECACHEEXPIRE); + Vector3 globalPos = new Vector3(); Vector3.TryParse(ad.GlobalPos, out globalPos); @@ -473,6 +570,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles uint queryParentEstate, UUID querySnapshotID, Vector3 queryGlobalPos, byte queryclassifiedFlags, int queryclassifiedPrice, IClientAPI remoteClient) { + Scene s = (Scene)remoteClient.Scene; Vector3 pos = remoteClient.SceneAgent.AbsolutePosition; ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y); @@ -486,6 +584,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } + // just flush cache for now + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.classifieds = null; + uce.classifiedsLists = null; + } + } + OSDMap parameters = new OSDMap {{"creatorId", OSD.FromUUID(creatorId)}}; OSD Params = (OSD)parameters; if (!rpc.JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString())) @@ -549,6 +658,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient) { + // just flush cache for now + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.classifieds = null; + uce.classifiedsLists = null; + } + } + string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); if(string.IsNullOrWhiteSpace(serverURI)) @@ -605,6 +725,19 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(targetId, out uce) && uce != null) + { + if(uce != null && uce.picksList != null) + { + remoteClient.SendAvatarPicksReply(targetId, uce.picksList); + return; + } + } + } + string serverURI = string.Empty; GetUserProfileServerURI(targetId, out serverURI); if(string.IsNullOrWhiteSpace(serverURI)) @@ -637,6 +770,14 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string name = m["name"].AsString(); picks[cid] = name; } + + if (uce == null) + uce = new UserProfileCacheEntry(); + uce.picksList = picks; + + lock(m_profilesCache) + m_profilesCache.AddOrUpdate(targetId, uce, PROFILECACHEEXPIRE); + remoteClient.SendAvatarPicksReply(targetId, picks); } @@ -667,8 +808,27 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(!UUID.TryParse (args [1], out pick.PickId)) return; + IClientAPI remoteClient = (IClientAPI)sender; + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(targetID, out uce) && uce != null) + { + if(uce != null && uce.picks != null && uce.picks.ContainsKey(pick.PickId)) + { + pick = uce.picks[pick.PickId]; + Vector3 gPos = new Vector3(Vector3.Zero); + Vector3.TryParse(pick.GlobalPos, out gPos); + remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name, + pick.Desc,pick.SnapshotId,pick.ParcelName,pick.OriginalName,pick.SimName, + gPos,pick.SortOrder,pick.Enabled); + return; + } + } + } + string serverURI = string.Empty; - GetUserProfileServerURI (targetID, out serverURI); + bool foreign = GetUserProfileServerURI (targetID, out serverURI); if(string.IsNullOrWhiteSpace(serverURI)) { return; @@ -676,8 +836,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string theirGatekeeperURI; GetUserGatekeeperURI(targetID, out theirGatekeeperURI); - - IClientAPI remoteClient = (IClientAPI)sender; object Pick = (object)pick; if (!rpc.JsonRpcRequest (ref Pick, "pickinforequest", serverURI, UUID.Random ().ToString ())) { @@ -686,6 +844,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } pick = (UserProfilePick)Pick; + if(foreign) + cacheForeignImage(targetID, pick.SnapshotId); Vector3 globalPos = new Vector3(Vector3.Zero); Vector3.TryParse(pick.GlobalPos, out globalPos); @@ -716,6 +876,16 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString()); + pick.GlobalPos = globalPos.ToString(); + if (uce == null) + uce = new UserProfileCacheEntry(); + if(uce.picks == null) + uce.picks = new Dictionary(); + uce.picks[pick.PickId] = pick; + + lock(m_profilesCache) + m_profilesCache.AddOrUpdate(targetID, uce, PROFILECACHEEXPIRE); + // Pull the rabbit out of the hat remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name, pick.Desc,pick.SnapshotId,pick.ParcelName,pick.OriginalName,pick.SimName, @@ -757,6 +927,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles //TODO: See how this works with NPC, May need to test m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString()); + // flush cache for now + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.picks = null; + uce.picksList = null; + } + } + UserProfilePick pick = new UserProfilePick(); string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); @@ -791,7 +972,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles avaPos.X, avaPos.Y, p.Scene.Name); } - pick.PickId = pickID; pick.CreatorId = creatorID; pick.TopPick = topPick; @@ -828,6 +1008,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// public void PickDelete(IClientAPI remoteClient, UUID queryPickID) { + // flush cache for now + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.picks = null; + uce.picksList = null; + } + } + string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); if(string.IsNullOrWhiteSpace(serverURI)) @@ -1025,6 +1216,16 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages) { + // flush cache for now + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.props = null; + } + } + UserProfileProperties prop = new UserProfileProperties(); prop.UserId = remoteClient.AgentId; @@ -1067,6 +1268,27 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles 0, "Getting into trouble", "Droidspeak"); return; } + UserProfileProperties props; + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(avatarID, out uce) && uce != null) + { + if(uce.props != null) + { + props = uce.props; + remoteClient.SendAvatarProperties(props.UserId, props.AboutText, + uce.born, uce.membershipType , props.FirstLifeText, uce.flags, + props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); + + + remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, + props.WantToText, (uint)props.SkillsMask, + props.SkillsText, props.Language); + return; + } + } + } string serverURI = string.Empty; bool foreign = GetUserProfileServerURI(avatarID, out serverURI); @@ -1118,13 +1340,13 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } - UserProfileProperties props = new UserProfileProperties(); + props = new UserProfileProperties(); props.UserId = avatarID; string result = string.Empty; - if(!GetProfileData(ref props, foreign, out result)) + if(!GetProfileData(ref props, foreign, serverURI, out result)) { - props.AboutText ="Profile not avaible at this time. User may still be unknown to this grid"; + props.AboutText ="Profile not available at this time. User may still be unknown to this grid"; } // if on same region force online @@ -1134,10 +1356,19 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(!m_allowUserProfileWebURLs) props.WebUrl =""; + if(uce == null) + uce = new UserProfileCacheEntry(); + uce.props = props; + uce.born = born; + uce.membershipType = membershipType; + uce.flags = flags; + + lock(m_profilesCache) + m_profilesCache.AddOrUpdate(props.UserId, uce, PROFILECACHEEXPIRE); + remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType , props.FirstLifeText, flags, props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); - remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask, props.SkillsText, props.Language); } @@ -1155,6 +1386,16 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if (remoteClient.AgentId == newProfile.ID) { + // flush cache for now + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.props = null; + } + } + UserProfileProperties prop = new UserProfileProperties(); prop.UserId = remoteClient.AgentId; @@ -1189,24 +1430,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// /// The profile data. /// - bool GetProfileData(ref UserProfileProperties properties, bool foreign, out string message) + bool GetProfileData(ref UserProfileProperties properties, bool foreign, string serverURI, out string message) { - // Can't handle NPC yet... - ScenePresence p = FindPresence(properties.UserId); - - if (null != p) - { - if (p.PresenceType == PresenceType.Npc) - { - message = "Id points to NPC"; - return false; - } - } - - string serverURI = string.Empty; - GetUserProfileServerURI(properties.UserId, out serverURI); - // This is checking a friend on the home grid - // Not HG friend if (String.IsNullOrEmpty(serverURI)) { message = "User profile service unknown at this time"; @@ -1247,10 +1472,14 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return false; } - // else, continue below } - + properties = (UserProfileProperties)Prop; + if(foreign) + { + cacheForeignImage(properties.UserId, properties.ImageId); + cacheForeignImage(properties.UserId, properties.FirstLifeImageId); + } message = "Success"; return true; @@ -1258,49 +1487,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles #endregion Avatar Properties #region Utils - bool GetImageAssets(UUID avatarId) - { - string profileServerURI = string.Empty; - string assetServerURI = string.Empty; - - bool foreign = GetUserProfileServerURI(avatarId, out profileServerURI); - - if(!foreign) - return true; - - assetServerURI = UserManagementModule.GetUserServerURL(avatarId, "AssetServerURI"); - - if(string.IsNullOrEmpty(profileServerURI) || string.IsNullOrEmpty(assetServerURI)) - return false; - - OSDMap parameters= new OSDMap(); - parameters.Add("avatarId", OSD.FromUUID(avatarId)); - OSD Params = (OSD)parameters; - if(!rpc.JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString())) - { - return false; - } - - parameters = (OSDMap)Params; - - if (parameters.ContainsKey("result")) - { - OSDArray list = (OSDArray)parameters["result"]; - - foreach (OSD asset in list) - { - OSDString assetId = (OSDString)asset; - - Scene.AssetService.Get(string.Format("{0}/{1}", assetServerURI, assetId.AsString())); - } - return true; - } - else - { - m_log.ErrorFormat("[PROFILES]: Problematic response for image_assets_request from {0}", profileServerURI); - return false; - } - } /// /// Gets the user account data. @@ -1451,6 +1637,27 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } + void cacheForeignImage(UUID agent, UUID imageID) + { + if(imageID == null || imageID == UUID.Zero) + return; + + string assetServerURI = UserManagementModule.GetUserServerURL(agent, "AssetServerURI"); + if(string.IsNullOrWhiteSpace(assetServerURI)) + return; + + string imageIDstr = imageID.ToString(); + + + if(m_assetCache != null && m_assetCache.Check(imageIDstr)) + return; + + if(Scene.AssetService.Get(imageIDstr) != null) + return; + + Scene.AssetService.Get(string.Format("{0}/{1}", assetServerURI, imageIDstr)); + } + /// /// Finds the presence. /// @@ -1519,9 +1726,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles webRequest.ContentType = "application/json-rpc"; webRequest.Method = "POST"; - Stream dataStream = webRequest.GetRequestStream(); - dataStream.Write(content, 0, content.Length); - dataStream.Close(); + using(Stream dataStream = webRequest.GetRequestStream()) + dataStream.Write(content,0,content.Length); WebResponse webResponse = null; try @@ -1601,9 +1807,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles webRequest.ContentType = "application/json-rpc"; webRequest.Method = "POST"; - Stream dataStream = webRequest.GetRequestStream(); - dataStream.Write(content, 0, content.Length); - dataStream.Close(); + using(Stream dataStream = webRequest.GetRequestStream()) + dataStream.Write(content,0,content.Length); WebResponse webResponse = null; try From 5571c499ba1658905c40a1d2d823031591649512 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 22 Dec 2016 07:06:40 +0000 Subject: [PATCH 204/305] UserProfileModule we can't use parcels globalID because we do not have a global locator. we need to send replies to viewer on pick update and delete --- .../Avatar/UserProfiles/UserProfileModule.cs | 65 ++++++++++++------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 3890bb294c..7a874e29d7 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -927,17 +927,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles //TODO: See how this works with NPC, May need to test m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString()); - // flush cache for now - UserProfileCacheEntry uce = null; - lock(m_profilesCache) - { - if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) - { - uce.picks = null; - uce.picksList = null; - } - } - UserProfilePick pick = new UserProfilePick(); string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); @@ -955,15 +944,19 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles avaPos.Z); string landParcelName = "My Parcel"; - UUID landParcelID = p.currentParcelUUID; +// UUID landParcelID = p.currentParcelUUID; + // to locate parcels we use a fake id that encodes the region handle + // since we do not have a global locator + // this fails on HG + UUID landParcelID = Util.BuildFakeParcelID(remoteClient.Scene.RegionInfo.RegionHandle, (uint)avaPos.X, (uint)avaPos.Y); ILandObject land = p.Scene.LandChannel.GetLandObject(avaPos.X, avaPos.Y); if (land != null) { // If land found, use parcel uuid from here because the value from SP will be blank if the avatar hasnt moved landParcelName = land.LandData.Name; - landParcelID = land.LandData.GlobalID; +// landParcelID = land.LandData.GlobalID; } else { @@ -994,6 +987,24 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(!m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + if(uce.picks == null) + uce.picks = new Dictionary(); + if(uce.picksList == null) + uce.picksList = new Dictionary(); + uce.picks[pick.PickId] = pick; + uce.picksList[pick.PickId] = pick.Name; + m_profilesCache.AddOrUpdate(remoteClient.AgentId, uce, PROFILECACHEEXPIRE); + } + remoteClient.SendAvatarPicksReply(remoteClient.AgentId, uce.picksList); + remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name, + pick.Desc,pick.SnapshotId,pick.ParcelName,pick.OriginalName,pick.SimName, + posGlobal,pick.SortOrder,pick.Enabled); + m_log.DebugFormat("[PROFILES]: Finish PickInfoUpdate {0} {1}", pick.Name, pick.PickId.ToString()); } @@ -1008,17 +1019,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// public void PickDelete(IClientAPI remoteClient, UUID queryPickID) { - // flush cache for now - UserProfileCacheEntry uce = null; - lock(m_profilesCache) - { - if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) - { - uce.picks = null; - uce.picksList = null; - } - } - string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); if(string.IsNullOrWhiteSpace(serverURI)) @@ -1035,6 +1035,23 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles "Error picks delete", false); return; } + + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + if(uce.picks != null && uce.picks.ContainsKey(queryPickID)) + uce.picks.Remove(queryPickID); + if(uce.picksList != null && uce.picksList.ContainsKey(queryPickID)) + uce.picksList.Remove(queryPickID); + m_profilesCache.AddOrUpdate(remoteClient.AgentId, uce, PROFILECACHEEXPIRE); + } + } + if(uce != null && uce.picksList != null) + remoteClient.SendAvatarPicksReply(remoteClient.AgentId, uce.picksList); + else + remoteClient.SendAvatarPicksReply(remoteClient.AgentId, new Dictionary()); } #endregion Picks From 84c3a96399f5233a075100739c270d0202aaaee8 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 22 Dec 2016 07:52:50 +0000 Subject: [PATCH 205/305] UserProfileModule refuse changes to classifieds outside home grid ( viewers may show a delete until profile is open again). Charge money only on classified creation sucess --- .../Avatar/UserProfiles/UserProfileModule.cs | 52 ++++++++++++++----- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 7a874e29d7..1ea1306d3d 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -570,29 +570,29 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles uint queryParentEstate, UUID querySnapshotID, Vector3 queryGlobalPos, byte queryclassifiedFlags, int queryclassifiedPrice, IClientAPI remoteClient) { - Scene s = (Scene)remoteClient.Scene; Vector3 pos = remoteClient.SceneAgent.AbsolutePosition; ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y); UUID creatorId = remoteClient.AgentId; ScenePresence p = FindPresence(creatorId); + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + m_profilesCache.TryGetValue(remoteClient.AgentId, out uce); + string serverURI = string.Empty; - GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); if(string.IsNullOrWhiteSpace(serverURI)) { return; } - // just flush cache for now - UserProfileCacheEntry uce = null; - lock(m_profilesCache) + if(foreign) { - if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) - { - uce.classifieds = null; - uce.classifiedsLists = null; - } + remoteClient.SendAgentAlertMessage("Please change classifieds on your home grid", true); + if(uce != null && uce.classifiedsLists != null) + remoteClient.SendAvatarClassifiedReply(remoteClient.AgentId, uce.classifiedsLists); + return; } OSDMap parameters = new OSDMap {{"creatorId", OSD.FromUUID(creatorId)}}; @@ -607,17 +607,20 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles bool exists = list.Cast().Where(map => map.ContainsKey("classifieduuid")) .Any(map => map["classifieduuid"].AsUUID().Equals(queryclassifiedID)); + IMoneyModule money = null; if (!exists) { - IMoneyModule money = s.RequestModuleInterface(); + money = s.RequestModuleInterface(); if (money != null) { if (!money.AmountCovered(remoteClient.AgentId, queryclassifiedPrice)) { remoteClient.SendAgentAlertMessage("You do not have enough money to create this classified.", false); + if(uce != null && uce.classifiedsLists != null) + remoteClient.SendAvatarClassifiedReply(remoteClient.AgentId, uce.classifiedsLists); return; } - money.ApplyCharge(remoteClient.AgentId, queryclassifiedPrice, MoneyTransactionType.ClassifiedCharge); +// money.ApplyCharge(remoteClient.AgentId, queryclassifiedPrice, MoneyTransactionType.ClassifiedCharge); } } @@ -644,7 +647,25 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(!rpc.JsonRpcRequest(ref Ad, "classified_update", serverURI, UUID.Random().ToString())) { remoteClient.SendAgentAlertMessage("Error updating classified", false); + if(uce != null && uce.classifiedsLists != null) + remoteClient.SendAvatarClassifiedReply(remoteClient.AgentId, uce.classifiedsLists); + return; } + + // only charge if it worked + if (money != null) + money.ApplyCharge(remoteClient.AgentId, queryclassifiedPrice, MoneyTransactionType.ClassifiedCharge); + + // just flush cache for now + lock(m_profilesCache) + { + if(uce != null) + { + uce.classifieds = null; + uce.classifiedsLists = null; + } + } + } /// @@ -670,10 +691,15 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } string serverURI = string.Empty; - GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); if(string.IsNullOrWhiteSpace(serverURI)) return; + if(foreign) + { + remoteClient.SendAgentAlertMessage("Please change classifieds on your home grid", true); + return; + } UUID classifiedId; if(!UUID.TryParse(queryClassifiedID.ToString(), out classifiedId)) return; From 5b403c448e5975a786d0edffe071a65c8a221adb Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 22 Dec 2016 15:37:48 +0000 Subject: [PATCH 206/305] Update the ini examples to add options missing from one to the other. Group hypergrid related options within each section to ease transition from non-HG to HG --- bin/Robust.HG.ini.example | 60 +++++++++++++++++++++++++++++++++------ bin/Robust.ini.example | 42 +++++++++++---------------- 2 files changed, 68 insertions(+), 34 deletions(-) diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index c231a8a5ca..b4e426af56 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -94,7 +94,13 @@ ;; Uncomment this if you want Groups V2 to work ; GroupsServiceConnector = "${Const|PrivatePort}/OpenSim.Addons.Groups.dll:GroupsServiceRobustConnector" ;; Uncomment to provide bakes caching - ;BakedTextureService = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:XBakesConnector" + ; BakedTextureService = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:XBakesConnector" + + ;; Uncomment for UserProfiles see [UserProfilesService] to configure... + ; UserProfilesServiceConnector = "${Const|PublicPort}/OpenSim.Server.Handlers.dll:UserProfilesConnector" + + ;; Uncomment if you want to have centralized estate data + ; EstateDataService = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:EstateDataRobustConnector" ;; Additions for Hypergrid @@ -108,12 +114,6 @@ ;; Uncomment this if you want Groups V2, HG to work ; HGGroupsServiceConnector = "${Const|PublicPort}/OpenSim.Addons.Groups.dll:HGGroupsServiceRobustConnector" - ;; Uncomment for UserProfiles see [UserProfilesService] to configure... - ; UserProfilesServiceConnector = "${Const|PublicPort}/OpenSim.Server.Handlers.dll:UserProfilesConnector" - - ;; Uncomment if you want to have centralized estate data - ; EstateDataService = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:EstateDataRobustConnector" - ; * This is common for all services, it's the network setup for the entire ; * server instance, if none is specified above ; * @@ -256,6 +256,18 @@ DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll" AssetLoaderArgs = "./assets/AssetSets.xml" + ; Allow maptile assets to remotely deleted by remote calls to the asset service. + ; There is no harm in having this as false - it just means that historical maptile assets are not deleted. + ; This only applies to maptiles served via the version 1 viewer mechanisms + ; Default is false + AllowRemoteDelete = false + + ; Allow all assets to be remotely deleted. + ; Only set this to true if you are operating a grid where you control all calls to the asset service + ; (where a necessary condition is that you control all simulators) and you need this for admin purposes. + ; If set to true, AllowRemoteDelete = true is required as well. + ; Default is false. + AllowRemoteDeleteAllTypes = false ; * This configuration loads the inventory server modules. It duplicates ; * the function of the legacy inventory server @@ -307,6 +319,7 @@ ;; ;; Persistent When the simulator is shutdown, the region is signalled as offline but left registered on the grid. ;; + ;; Example specification: ; Region_Welcome_Area = "DefaultRegion, FallbackRegion" ; (replace spaces with underscore) @@ -431,6 +444,9 @@ ; for the server connector LocalServiceModule = "OpenSim.Services.PresenceService.dll:PresenceService" + ; Set this to true to allow the use of advanced web services and multiple + ; bots using one account + AllowDuplicatePresences = false; [AvatarService] ; for the server connector @@ -462,14 +478,21 @@ GridService = "OpenSim.Services.GridService.dll:GridService" SimulationService ="OpenSim.Services.Connectors.dll:SimulationServiceConnector" LibraryService = "OpenSim.Services.InventoryService.dll:LibraryService" - UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService" + ; The minimum user level required for a user to be able to login. 0 by default + ; If you disable a particular user's account then you can set their login level below this number. + ; You can also change this level from the console though these changes will not be persisted. + ; MinLoginLevel = 0 + + ;; for hypergrid + UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" ; This inventory service will be used to initialize the user's inventory HGInventoryServicePlugin = "OpenSim.Services.HypergridService.dll:HGSuitcaseInventoryService" HGInventoryServiceConstructorArg = "HGInventoryService" + ;; end hypergrid - ;; Ask co-operative viewers to use a different currency name + ; Ask co-operative viewers to use a different currency name ;Currency = "" ;; Set minimum fee to publish classified @@ -517,6 +540,24 @@ ;; 'America/Los_Angeles' is used on Linux/Mac systems whilst 'Pacific Standard Time' is used on Windows DSTZone = "America/Los_Angeles;Pacific Standard Time" + ;Basic Login Service Dos Protection Tweaks + ;; + ;; Some Grids/Users use a transparent proxy that makes use of the X-Forwarded-For HTTP Header, If you do, set this to true + ;; If you set this to true and you don't have a transparent proxy, it may allow attackers to put random things in the X-Forwarded-For header to + ;; get around this basic DOS protection. + ;DOSAllowXForwardedForHeader = false + ;; + ;; The protector adds up requests during this rolling period of time, default 10 seconds + ;DOSRequestTimeFrameMS = 10000 + ;; + ;; The amount of requests in the above timeframe from the same endpoint that triggers protection + ;DOSMaxRequestsInTimeFrame = 5 + ;; + ;; The amount of time that a specific endpoint is blocked. Default 2 minutes. + ;DOSForgiveClientAfterMS = 120000 + ;; + ;; To turn off basic dos protection, set the DOSMaxRequestsInTimeFrame to 0. + [MapImageService] LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService" @@ -749,6 +790,7 @@ ;; What is the HomeURI of users associated with this grid? ;; Can overwrite the default in [Hypergrid], but probably shouldn't ; HomeURI = "${Const|BaseURL}:${Const|PublicPort}" + ;; end hypergrid ;; Sets the maximum number of groups an agent may join ; MaxAgentGroups = 42 diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 743b23dbc5..7c9f6daf70 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -81,11 +81,11 @@ MapAddServiceConnector = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:MapAddServiceConnector" MapGetServiceConnector = "${Const|PublicPort}/OpenSim.Server.Handlers.dll:MapGetServiceConnector" ;; Uncomment this if you want offline IM to work - ;OfflineIMServiceConnector = "${Const|PrivatePort}/OpenSim.Addons.OfflineIM.dll:OfflineIMServiceRobustConnector" + ; OfflineIMServiceConnector = "${Const|PrivatePort}/OpenSim.Addons.OfflineIM.dll:OfflineIMServiceRobustConnector" ;; Uncomment this if you want Groups V2 to work - ;GroupsServiceConnector = "${Const|PrivatePort}/OpenSim.Addons.Groups.dll:GroupsServiceRobustConnector" + ; GroupsServiceConnector = "${Const|PrivatePort}/OpenSim.Addons.Groups.dll:GroupsServiceRobustConnector" ;; Uncomment to provide bakes caching - ;BakedTextureService = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:XBakesConnector" + ; BakedTextureService = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:XBakesConnector" ;; Uncomment for UserProfiles see [UserProfilesService] to configure... ; UserProfilesServiceConnector = "${Const|PublicPort}/OpenSim.Server.Handlers.dll:UserProfilesConnector" @@ -214,7 +214,7 @@ ;; The following are common to both the default asset service and FSAsset service - ;; Default loader for loading default assets from XML on first run + ;; Common asset service options DefaultAssetLoader = "OpenSim.Framework.AssetLoader.Filesystem.dll" AssetLoaderArgs = "./assets/AssetSets.xml" @@ -324,6 +324,7 @@ [AuthenticationService] ; for the server connector LocalServiceModule = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" + ; Realm = "useraccounts" ;; Allow the service to process HTTP getauthinfo calls. ;; Default is false. @@ -344,8 +345,8 @@ UserAccountServiceModule = "OpenSim.Services.UserAccountService.dll:UserAccountService" -; * This is the new style authentication service. Currently, only MySQL -; * is implemented. "Realm" is the table that is used for user lookup. +; * This is the new style user service. +; * "Realm" is the table that is used for user lookup. ; * It defaults to "useraccounts", which uses the new style. ; * Realm = "users" will use the legacy tables as an authentication source ; * @@ -455,15 +456,6 @@ ; If you run this login server behind a proxy, set this to true ; HasProxy = false - ;# {DSTZone} {} {Override Daylight Saving Time rules} {* none local} "America/Los_Angeles;Pacific Standard Time" - ;; Viewers do not listen to timezone sent by the server. They use Pacific Standard Time instead, - ;; but rely on the server to calculate Daylight Saving Time. Sending another DST than US Pacific - ;; would result in time inconsistencies between grids (during summer and around DST transition period) - ;; default let OpenSim calculate US Pacific DST - ;; "none" disable DST (equivallent to "local" with system set to GMT) - ;; "local" force legacy behaviour (using local system time to calculate DST) - ; DSTZone = "America/Los_Angeles;Pacific Standard Time" - ;# {DSTZone} {} {Override Daylight Saving Time rules} {* none local} "America/Los_Angeles;Pacific Standard Time" ;; Viewers do not receive timezone information from the server - almost all (?) default to Pacific Standard Time ;; However, they do rely on the server to tell them whether it's Daylight Saving Time or not. @@ -509,16 +501,6 @@ ; HasProxy = false -[Messaging] - ; OfflineIM - OfflineIMService = "OpenSim.Addons.OfflineIM.dll:OfflineIMService" - - -[Groups] - ;; Sets the maximum number of groups an agent may join - ; MaxAgentGroups = 42 - - [GridInfoService] ; These settings are used to return information on a get_grid_info call. ; Client launcher scripts and third-party clients make use of this to @@ -559,6 +541,16 @@ ;password = ${Const|BaseURL}/password +[Messaging] + ; OfflineIM + OfflineIMService = "OpenSim.Addons.OfflineIM.dll:OfflineIMService" + + +[Groups] + ;; Sets the maximum number of groups an agent may join + ; MaxAgentGroups = 42 + + [UserProfilesService] LocalServiceModule = "OpenSim.Services.UserProfilesService.dll:UserProfilesService" Enabled = false From 0ae2b5ac8134230fd5f1bcd668647afb5b345baf Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 22 Dec 2016 18:23:04 +0000 Subject: [PATCH 207/305] Allow the use of modular configs with Robust as we already can with OpenSim --- OpenSim/Server/Base/ServicesServerBase.cs | 148 ++++++++++++++++++---- bin/Robust.HG.ini.example | 2 +- bin/Robust.ini.example | 2 +- 3 files changed, 125 insertions(+), 27 deletions(-) diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs index a7cffd7958..e18594f5e3 100644 --- a/OpenSim/Server/Base/ServicesServerBase.cs +++ b/OpenSim/Server/Base/ServicesServerBase.cs @@ -55,11 +55,7 @@ namespace OpenSim.Server.Base // protected string[] m_Arguments; - public string ConfigDirectory - { - get; - private set; - } + protected string m_configDirectory = "."; // Run flag // @@ -101,31 +97,24 @@ namespace OpenSim.Server.Base logConfig =startupConfig.GetString("logconfig", logConfig); } - // Find out of the file name is a URI and remote load it if possible. - // Load it as a local file otherwise. - Uri configUri; + Config = ReadConfigSource(iniFile); - try + List sources = new List(); + sources.Add(iniFile); + + int sourceIndex = 1; + + while (AddIncludes(Config, sources)) { - if (Uri.TryCreate(iniFile, UriKind.Absolute, out configUri) && - configUri.Scheme == Uri.UriSchemeHttp) + for ( ; sourceIndex < sources.Count ; ++sourceIndex) { - XmlReader r = XmlReader.Create(iniFile); - Config = new XmlConfigSource(r); + IConfigSource s = ReadConfigSource(sources[sourceIndex]); + Config.Merge(s); } - else - { - Config = new IniConfigSource(iniFile); - } - } - catch (Exception e) - { - System.Console.WriteLine("Error reading from config source. {0}", e.Message); - Environment.Exit(1); } // Merge OpSys env vars - m_log.Info("[CONFIG]: Loading environment variables for Config"); + Console.WriteLine("[CONFIG]: Loading environment variables for Config"); Util.MergeEnvironmentToConfig(Config); // Merge the configuration from the command line into the loaded file @@ -141,7 +130,7 @@ namespace OpenSim.Server.Base if (startupConfig != null) { - ConfigDirectory = startupConfig.GetString("ConfigDirectory", "."); + m_configDirectory = startupConfig.GetString("ConfigDirectory", m_configDirectory); prompt = startupConfig.GetString("Prompt", prompt); } @@ -241,5 +230,114 @@ namespace OpenSim.Server.Base protected virtual void Initialise() { } + + /// + /// Adds the included files as ini configuration files + /// + /// List of URL strings or filename strings + private bool AddIncludes(IConfigSource configSource, List sources) + { + bool sourcesAdded = false; + + //loop over config sources + foreach (IConfig config in configSource.Configs) + { + // Look for Include-* in the key name + string[] keys = config.GetKeys(); + foreach (string k in keys) + { + if (k.StartsWith("Include-")) + { + // read the config file to be included. + string file = config.GetString(k); + if (IsUri(file)) + { + if (!sources.Contains(file)) + { + sourcesAdded = true; + sources.Add(file); + } + } + else + { + string basepath = Path.GetFullPath(m_configDirectory); + // Resolve relative paths with wildcards + string chunkWithoutWildcards = file; + string chunkWithWildcards = string.Empty; + int wildcardIndex = file.IndexOfAny(new char[] { '*', '?' }); + if (wildcardIndex != -1) + { + chunkWithoutWildcards = file.Substring(0, wildcardIndex); + chunkWithWildcards = file.Substring(wildcardIndex); + } + string path = Path.Combine(basepath, chunkWithoutWildcards); + path = Path.GetFullPath(path) + chunkWithWildcards; + string[] paths = Util.Glob(path); + + // If the include path contains no wildcards, then warn the user that it wasn't found. + if (wildcardIndex == -1 && paths.Length == 0) + { + Console.WriteLine("[CONFIG]: Could not find include file {0}", path); + } + else + { + foreach (string p in paths) + { + if (!sources.Contains(p)) + { + sourcesAdded = true; + sources.Add(p); + } + } + } + } + } + } + } + + return sourcesAdded; + } + + /// + /// Check if we can convert the string to a URI + /// + /// String uri to the remote resource + /// true if we can convert the string to a Uri object + bool IsUri(string file) + { + Uri configUri; + + return Uri.TryCreate(file, UriKind.Absolute, + out configUri) && configUri.Scheme == Uri.UriSchemeHttp; + } + + IConfigSource ReadConfigSource(string iniFile) + { + // Find out of the file name is a URI and remote load it if possible. + // Load it as a local file otherwise. + Uri configUri; + IConfigSource s = null; + + try + { + if (Uri.TryCreate(iniFile, UriKind.Absolute, out configUri) && + configUri.Scheme == Uri.UriSchemeHttp) + { + XmlReader r = XmlReader.Create(iniFile); + s = new XmlConfigSource(r); + } + else + { + s = new IniConfigSource(iniFile); + } + } + catch (Exception e) + { + System.Console.WriteLine("Error reading from config source. {0}", e.Message); + Environment.Exit(1); + } + + return s; + } } -} \ No newline at end of file +} diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index b4e426af56..20c080475e 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -58,7 +58,7 @@ ; Modular configurations ; Set path to directory for modular ini files... ; The Robust.exe process must have R/W access to the location - ConfigDirectory = "." + ConfigDirectory = "robust-include" ; Console commands can be saved to a file, so the command history persists after a restart. (default is true) ConsoleHistoryFileEnabled = true diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 7c9f6daf70..d33178c461 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -50,7 +50,7 @@ ; Modular configurations ; Set path to directory for modular ini files... ; The Robust.exe process must have R/W access to the location - ConfigDirectory = "." + ConfigDirectory = "robust-include" ; Console commands can be saved to a file, so the command history persists after a restart. (default is true) ConsoleHistoryFileEnabled = true From 2e7e4427d06951e950019b4175f6dba9358c4d0d Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 23 Dec 2016 02:17:42 +0000 Subject: [PATCH 208/305] UserProfileModule threading issues --- .../Avatar/UserProfiles/UserProfileModule.cs | 140 ++++++++++-------- 1 file changed, 77 insertions(+), 63 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 1ea1306d3d..d232d82a84 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -438,12 +438,14 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } - if(uce == null) - uce = new UserProfileCacheEntry(); - uce.classifiedsLists = classifieds; + lock(m_profilesCache) + { + if(!m_profilesCache.TryGetValue(targetID, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + uce.classifiedsLists = classifieds; - lock(m_profilesCache) m_profilesCache.AddOrUpdate(targetID, uce, PROFILECACHEEXPIRE); + } remoteClient.SendAvatarClassifiedReply(targetID, classifieds); } @@ -512,14 +514,16 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(foreign) cacheForeignImage(target, ad.SnapshotId); - if(uce == null) - uce = new UserProfileCacheEntry(); - if(uce.classifieds == null) - uce.classifieds = new Dictionary(); - uce.classifieds[ad.ClassifiedId] = ad; - lock(m_profilesCache) - m_profilesCache.AddOrUpdate(ad.ClassifiedId, uce, PROFILECACHEEXPIRE); + { + if(!m_profilesCache.TryGetValue(target, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + if(uce.classifieds == null) + uce.classifieds = new Dictionary(); + uce.classifieds[ad.ClassifiedId] = ad; + + m_profilesCache.AddOrUpdate(target, uce, PROFILECACHEEXPIRE); + } Vector3 globalPos = new Vector3(); Vector3.TryParse(ad.GlobalPos, out globalPos); @@ -659,7 +663,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles // just flush cache for now lock(m_profilesCache) { - if(uce != null) + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) { uce.classifieds = null; uce.classifiedsLists = null; @@ -679,16 +683,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient) { - // just flush cache for now - UserProfileCacheEntry uce = null; - lock(m_profilesCache) - { - if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) - { - uce.classifieds = null; - uce.classifiedsLists = null; - } - } string serverURI = string.Empty; bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); @@ -700,6 +694,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles remoteClient.SendAgentAlertMessage("Please change classifieds on your home grid", true); return; } + UUID classifiedId; if(!UUID.TryParse(queryClassifiedID.ToString(), out classifiedId)) return; @@ -714,6 +709,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } + // flush cache + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.classifieds = null; + uce.classifiedsLists = null; + } + } + parameters = (OSDMap)Params; } #endregion Classified @@ -797,12 +803,14 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles picks[cid] = name; } - if (uce == null) - uce = new UserProfileCacheEntry(); - uce.picksList = picks; - lock(m_profilesCache) + { + if(!m_profilesCache.TryGetValue(targetId, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + uce.picksList = picks; + m_profilesCache.AddOrUpdate(targetId, uce, PROFILECACHEEXPIRE); + } remoteClient.SendAvatarPicksReply(targetId, picks); } @@ -903,14 +911,16 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString()); pick.GlobalPos = globalPos.ToString(); - if (uce == null) - uce = new UserProfileCacheEntry(); - if(uce.picks == null) - uce.picks = new Dictionary(); - uce.picks[pick.PickId] = pick; - lock(m_profilesCache) + { + if(!m_profilesCache.TryGetValue(targetID, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + if(uce.picks == null) + uce.picks = new Dictionary(); + uce.picks[pick.PickId] = pick; + m_profilesCache.AddOrUpdate(targetID, uce, PROFILECACHEEXPIRE); + } // Pull the rabbit out of the hat remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name, @@ -950,7 +960,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// public void PickInfoUpdate(IClientAPI remoteClient, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled) { - //TODO: See how this works with NPC, May need to test m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString()); UserProfilePick pick = new UserProfilePick(); @@ -1067,11 +1076,11 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) { - if(uce.picks != null && uce.picks.ContainsKey(queryPickID)) - uce.picks.Remove(queryPickID); - if(uce.picksList != null && uce.picksList.ContainsKey(queryPickID)) - uce.picksList.Remove(queryPickID); - m_profilesCache.AddOrUpdate(remoteClient.AgentId, uce, PROFILECACHEEXPIRE); + if(uce.picks != null && uce.picks.ContainsKey(queryPickID)) + uce.picks.Remove(queryPickID); + if(uce.picksList != null && uce.picksList.ContainsKey(queryPickID)) + uce.picksList.Remove(queryPickID); + m_profilesCache.AddOrUpdate(remoteClient.AgentId, uce, PROFILECACHEEXPIRE); } } if(uce != null && uce.picksList != null) @@ -1259,15 +1268,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages) { - // flush cache for now - UserProfileCacheEntry uce = null; - lock(m_profilesCache) - { - if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) - { - uce.props = null; - } - } UserProfileProperties prop = new UserProfileProperties(); @@ -1290,6 +1290,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles "Error updating interests", false); return; } + + // flush cache + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.props = null; + } + } + } public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) @@ -1399,15 +1410,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(!m_allowUserProfileWebURLs) props.WebUrl =""; - if(uce == null) - uce = new UserProfileCacheEntry(); - uce.props = props; - uce.born = born; - uce.membershipType = membershipType; - uce.flags = flags; - lock(m_profilesCache) + { + if(!m_profilesCache.TryGetValue(props.UserId, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + uce.props = props; + uce.born = born; + uce.membershipType = membershipType; + uce.flags = flags; + m_profilesCache.AddOrUpdate(props.UserId, uce, PROFILECACHEEXPIRE); + } remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType , props.FirstLifeText, flags, props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); @@ -1429,15 +1442,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if (remoteClient.AgentId == newProfile.ID) { - // flush cache for now - UserProfileCacheEntry uce = null; - lock(m_profilesCache) - { - if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) - { - uce.props = null; - } - } UserProfileProperties prop = new UserProfileProperties(); @@ -1463,6 +1467,16 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } + // flush cache + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.props = null; + } + } + RequestAvatarProperties(remoteClient, newProfile.ID); } } From 0887be3c12f548539dd5a66d11c74a2f118cac5f Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 23 Dec 2016 03:42:50 +0000 Subject: [PATCH 209/305] replace the (hidden) GRID_GOD by a more usefull GOD so includes all types. This needs to be changed to current effective godlevel check (sp.GodLevel) when that is fixed. Automatic god powers need be (optionaly) removed --- .../ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 8 +++++--- bin/config-include/osslEnable.ini | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 5638f01cba..6e6647911c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -310,7 +310,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (string id in ids) { string current = id.Trim(); - if (current.ToUpper() == "PARCEL_GROUP_MEMBER" || current.ToUpper() == "PARCEL_OWNER" || current.ToUpper() == "ESTATE_MANAGER" || current.ToUpper() == "ESTATE_OWNER" || current.ToUpper() == "GRID_GOD") + if (current.ToUpper() == "PARCEL_GROUP_MEMBER" || current.ToUpper() == "PARCEL_OWNER" || current.ToUpper() == "ESTATE_MANAGER" || current.ToUpper() == "ESTATE_OWNER" || current.ToUpper() == "GOD") { if (!perms.AllowedOwnerClasses.Contains(current)) perms.AllowedOwnerClasses.Add(current.ToUpper()); @@ -416,9 +416,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } //Only gods may use the function - if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("GRID_GOD")) + if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("GOD")) { - if (World.Permissions.IsGridGod(ownerID)) + // this should be replaced by sp.GodLevel > 200 to be effective requested power + // but that still needs fix + if (World.Permissions.IsGod(ownerID)) { return String.Empty; } diff --git a/bin/config-include/osslEnable.ini b/bin/config-include/osslEnable.ini index a064f0957f..21e14519e0 100644 --- a/bin/config-include/osslEnable.ini +++ b/bin/config-include/osslEnable.ini @@ -37,6 +37,7 @@ ; To enable for individuals or groups, set it to a comma separated list. This checks ; against the owner of the object containing the script. ; The comma separated entries in the list may be one of: + ; "GOD" -- enable for users with GOD rights ; "ESTATE_MANAGER" -- enable for estate manager ; "ESTATE_OWNER" -- enable for estate owner ; "PARCEL_OWNER" -- enable for parcel owner From b6266c6a1de9d78904aa01eb39f1da2979db06ca Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 23 Dec 2016 14:23:07 +0000 Subject: [PATCH 210/305] check if a parcelID is a encoded position data or a true UUID. This may fail, just reducing the odds. --- OpenSim/Framework/Util.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index b6225232db..89cf045716 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1725,12 +1725,16 @@ namespace OpenSim.Framework return new UUID(bytes, 0); } - public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) + public static bool ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) { byte[] bytes = parcelID.GetBytes(); regionHandle = Utils.BytesToUInt64(bytes); x = Utils.BytesToUInt(bytes, 8) & 0xffff; y = Utils.BytesToUInt(bytes, 12) & 0xffff; + // validation may fail, just reducing the odds of using a real UUID as encoded parcel + return ( bytes[0] == 0 && bytes[4] == 0 && // handler x,y multiples of 256 + bytes[9] < 64 && bytes[13] < 64 && // positions < 16km + bytes[14] == 0 && bytes[15] == 0); } public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z) From 70475c676bbb9ed3a029a5c28c8e253e7df35d97 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 23 Dec 2016 14:25:22 +0000 Subject: [PATCH 211/305] dont try to use a parcelID as encoded position when it is not --- .../Region/CoreModules/World/Land/LandManagementModule.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index bec5322341..22bc49e3c1 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -1880,8 +1880,9 @@ namespace OpenSim.Region.CoreModules.World.Land UUID.TryParse(id, out parcel); // assume we've got the parcelID we just computed in RemoteParcelRequest ExtendedLandData extLandData = new ExtendedLandData(); - Util.ParseFakeParcelID(parcel, out extLandData.RegionHandle, - out extLandData.X, out extLandData.Y); + if(!Util.ParseFakeParcelID(parcel, out extLandData.RegionHandle, + out extLandData.X, out extLandData.Y)) + return null; m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Got parcelinfo request for regionHandle {0}, x/y {1}/{2}", extLandData.RegionHandle, extLandData.X, extLandData.Y); From bfb1cb9f33ab4beb01661e7fb14678e8b009e384 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 23 Dec 2016 16:10:07 +0000 Subject: [PATCH 212/305] a few more changes on user profiles --- .../Avatar/UserProfiles/UserProfileModule.cs | 96 +++++++++++++++---- 1 file changed, 76 insertions(+), 20 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index d232d82a84..3f7a8ee7a9 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -897,20 +897,36 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles else { // we have a proxy on map - // this is a fail on large regions - uint gtmp = (uint)globalPos.X >> 8; - globalPos.X -= (gtmp << 8); - globalPos.X += target.RegionLocX; + ulong oriHandle; + uint oriX; + uint oriY; + if(Util.ParseFakeParcelID(pick.ParcelId, out oriHandle, out oriX, out oriY)) + { + pick.ParcelId = Util.BuildFakeParcelID(target.RegionHandle, oriX, oriY); + globalPos.X = target.RegionLocX + oriX; + globalPos.Y = target.RegionLocY + oriY; + pick.GlobalPos = globalPos.ToString(); + } + else + { + // this is a fail on large regions + uint gtmp = (uint)globalPos.X >> 8; + globalPos.X -= (gtmp << 8); - gtmp = (uint)globalPos.Y >> 8; - globalPos.Y -= (gtmp << 8); - globalPos.Y += target.RegionLocY; + gtmp = (uint)globalPos.Y >> 8; + globalPos.Y -= (gtmp << 8); + + pick.ParcelId = Util.BuildFakeParcelID(target.RegionHandle, (uint)globalPos.X, (uint)globalPos.Y); + + globalPos.X += target.RegionLocX; + globalPos.Y += target.RegionLocY; + pick.GlobalPos = globalPos.ToString(); + } } } m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString()); - pick.GlobalPos = globalPos.ToString(); lock(m_profilesCache) { if(!m_profilesCache.TryGetValue(targetID, out uce) || uce == null) @@ -1331,16 +1347,35 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(uce.props != null) { props = uce.props; - remoteClient.SendAvatarProperties(props.UserId, props.AboutText, - uce.born, uce.membershipType , props.FirstLifeText, uce.flags, - props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); + uint cflags = uce.flags; + // if on same region force online + if(p != null && !p.IsDeleted) + cflags |= 0x10; + remoteClient.SendAvatarProperties(props.UserId, props.AboutText, + uce.born, uce.membershipType , props.FirstLifeText, cflags, + props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask, props.SkillsText, props.Language); - return; + return; } + else + { + if(uce.ClientsWaitingProps == null) + uce.ClientsWaitingProps = new HashSet(); + else if(uce.ClientsWaitingProps.Contains(remoteClient)) + return; + uce.ClientsWaitingProps.Add(remoteClient); + } + } + else + { + uce = new UserProfileCacheEntry(); + uce.ClientsWaitingProps = new HashSet(); + uce.ClientsWaitingProps.Add(remoteClient); + m_profilesCache.AddOrUpdate(avatarID, uce, PROFILECACHEEXPIRE); } } @@ -1402,14 +1437,11 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { props.AboutText ="Profile not available at this time. User may still be unknown to this grid"; } - - // if on same region force online - if(p != null && !p.IsDeleted) - flags |= 0x10; if(!m_allowUserProfileWebURLs) props.WebUrl =""; + HashSet clients; lock(m_profilesCache) { if(!m_profilesCache.TryGetValue(props.UserId, out uce) || uce == null) @@ -1418,15 +1450,39 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles uce.born = born; uce.membershipType = membershipType; uce.flags = flags; - + clients = uce.ClientsWaitingProps; + uce.ClientsWaitingProps = null; m_profilesCache.AddOrUpdate(props.UserId, uce, PROFILECACHEEXPIRE); } - remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType , props.FirstLifeText, flags, + // if on same region force online + if(p != null && !p.IsDeleted) + flags |= 0x10; + + if(clients == null) + { + remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType , props.FirstLifeText, flags, props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); - remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask, - props.SkillsText, props.Language); + remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, + (uint)props.SkillsMask, props.SkillsText, props.Language); + } + else + { + if(!clients.Contains(remoteClient)) + clients.Add(remoteClient); + foreach(IClientAPI cli in clients) + { + if(!cli.IsActive) + continue; + cli.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType , props.FirstLifeText, flags, + props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); + + cli.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, + (uint)props.SkillsMask, props.SkillsText, props.Language); + + } + } } /// From 679d52ced69adecaa510b7b196a1d13c59fc836c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 23 Dec 2016 19:41:57 +0000 Subject: [PATCH 213/305] add missing file --- OpenSim/Framework/UserProfiles.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs index 6d46fe9c2d..4ed890bc43 100644 --- a/OpenSim/Framework/UserProfiles.cs +++ b/OpenSim/Framework/UserProfiles.cs @@ -135,6 +135,7 @@ namespace OpenSim.Framework public string born; public byte[] membershipType; public uint flags; + public HashSet ClientsWaitingProps; } } From ba1ca67afef3640bd5fd0d1cee678d7bda79c97c Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Fri, 23 Dec 2016 19:48:03 +0000 Subject: [PATCH 214/305] Re-add GRID_GOD because in some cases an "employee-only" level is simply needed --- .../Shared/Api/Implementation/OSSL_Api.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 6e6647911c..ba5a46d1be 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -310,7 +310,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (string id in ids) { string current = id.Trim(); - if (current.ToUpper() == "PARCEL_GROUP_MEMBER" || current.ToUpper() == "PARCEL_OWNER" || current.ToUpper() == "ESTATE_MANAGER" || current.ToUpper() == "ESTATE_OWNER" || current.ToUpper() == "GOD") + if (current.ToUpper() == "PARCEL_GROUP_MEMBER" || current.ToUpper() == "PARCEL_OWNER" || current.ToUpper() == "ESTATE_MANAGER" || current.ToUpper() == "ESTATE_OWNER" || current.ToUpper() == "GOD" || current.ToUpper() == "GRID_GOD") { if (!perms.AllowedOwnerClasses.Contains(current)) perms.AllowedOwnerClasses.Add(current.ToUpper()); @@ -418,14 +418,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api //Only gods may use the function if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("GOD")) { - // this should be replaced by sp.GodLevel > 200 to be effective requested power - // but that still needs fix if (World.Permissions.IsGod(ownerID)) { return String.Empty; } } + //Only grid gods may use the function + if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("GRID_GOD")) + { + if (World.Permissions.IsGridGod(ownerID)) + { + return String.Empty; + } + } + if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID)) return( String.Format("{0} permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission.", From 8d0b592e5d3524cf57a1a12edd0eb6fd2ce25dff Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Fri, 23 Dec 2016 20:41:10 +0000 Subject: [PATCH 215/305] Add en explanation to osslEnable.ini for GRID_GOD --- bin/config-include/osslEnable.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/config-include/osslEnable.ini b/bin/config-include/osslEnable.ini index 21e14519e0..b96688bafd 100644 --- a/bin/config-include/osslEnable.ini +++ b/bin/config-include/osslEnable.ini @@ -37,7 +37,8 @@ ; To enable for individuals or groups, set it to a comma separated list. This checks ; against the owner of the object containing the script. ; The comma separated entries in the list may be one of: - ; "GOD" -- enable for users with GOD rights + ; "GRID_GOD" -- enable for users with UserLevel >= 200 + ; "GOD" -- enable for users with any type of god rights ; "ESTATE_MANAGER" -- enable for estate manager ; "ESTATE_OWNER" -- enable for estate owner ; "PARCEL_OWNER" -- enable for parcel owner From 293b65ac82890f338b6ed420ca7e56f876e79f40 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 25 Dec 2016 05:46:16 +0000 Subject: [PATCH 216/305] FloatSamCache: dont use slideexpire on current libovm expirecache. Change example settings to use memory cache with short expire time. ( 20% to 40% mem cache hit rates observed --- .../CoreModules/Asset/FlotsamAssetCache.cs | 75 ++++++++++++------- bin/config-include/FlotsamCache.ini.example | 13 +++- 2 files changed, 58 insertions(+), 30 deletions(-) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 9413598de6..b6dd5652c7 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -62,7 +62,8 @@ namespace OpenSim.Region.CoreModules.Asset MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled; - private bool m_Running; + private bool m_timerRunning; + private bool m_cleanupRunning; private const string m_ModuleName = "FlotsamAssetCache"; private const string m_DefaultCacheDirectory = "./assetcache"; @@ -91,9 +92,8 @@ namespace OpenSim.Region.CoreModules.Asset private bool m_MemoryCacheEnabled = false; // Expiration is expressed in hours. - private const double m_DefaultMemoryExpiration = 2; + private double m_MemoryExpiration = 0.001; private const double m_DefaultFileExpiration = 48; - private TimeSpan m_MemoryExpiration = TimeSpan.FromHours(m_DefaultMemoryExpiration); private TimeSpan m_FileExpiration = TimeSpan.FromHours(m_DefaultFileExpiration); private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(1.0); @@ -150,7 +150,8 @@ namespace OpenSim.Region.CoreModules.Asset m_CacheDirectory = assetConfig.GetString("CacheDirectory", m_DefaultCacheDirectory); m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled); - m_MemoryExpiration = TimeSpan.FromHours(assetConfig.GetDouble("MemoryCacheTimeout", m_DefaultMemoryExpiration)); + m_MemoryExpiration = assetConfig.GetDouble("MemoryCacheTimeout", m_MemoryExpiration); + m_MemoryExpiration *= 3600.0; // config in hours to seconds #if WAIT_ON_INPROGRESS_REQUESTS m_WaitOnInprogressTimeout = assetConfig.GetInt("WaitOnInprogressTimeout", 3000); @@ -224,9 +225,9 @@ namespace OpenSim.Region.CoreModules.Asset m_Scenes.Remove(scene); lock(timerLock) { - if(m_Running && m_Scenes.Count <= 0) + if(m_timerRunning && m_Scenes.Count <= 0) { - m_Running = false; + m_timerRunning = false; m_CacheCleanTimer.Stop(); m_CacheCleanTimer.Close(); } @@ -242,7 +243,7 @@ namespace OpenSim.Region.CoreModules.Asset m_AssetService = scene.RequestModuleInterface(); lock(timerLock) { - if(!m_Running) + if(!m_timerRunning) { if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) { @@ -250,7 +251,7 @@ namespace OpenSim.Region.CoreModules.Asset m_CacheCleanTimer.AutoReset = false; m_CacheCleanTimer.Elapsed += CleanupExpiredFiles; m_CacheCleanTimer.Start(); - m_Running = true; + m_timerRunning = true; } } } @@ -263,6 +264,7 @@ namespace OpenSim.Region.CoreModules.Asset private void UpdateMemoryCache(string key, AssetBase asset) { + // NOTE DO NOT USE SLIDEEXPIRE option on current libomv m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration); } @@ -480,12 +482,10 @@ namespace OpenSim.Region.CoreModules.Asset asset = GetFromMemoryCache(id); if (asset == null && m_FileCacheEnabled) - { asset = GetFromFileCache(id); - if (m_MemoryCacheEnabled && asset != null) - UpdateMemoryCache(id, asset); - } + if (m_MemoryCacheEnabled && asset != null) + UpdateMemoryCache(id, asset); if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0)) { @@ -561,8 +561,12 @@ namespace OpenSim.Region.CoreModules.Asset if (m_LogLevel >= 2) m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration); - if(!m_Running) - return; + lock(timerLock) + { + if(!m_timerRunning || m_cleanupRunning) + return; + m_cleanupRunning = true; + } // Purge all files last accessed prior to this point DateTime purgeLine = DateTime.Now - m_FileExpiration; @@ -578,8 +582,9 @@ namespace OpenSim.Region.CoreModules.Asset lock(timerLock) { - if(m_Running) + if(m_timerRunning) m_CacheCleanTimer.Start(); + m_cleanupRunning = false; } } @@ -816,13 +821,13 @@ namespace OpenSim.Region.CoreModules.Asset s.ForEachSOG(delegate(SceneObjectGroup e) { - if(!m_Running && !storeUncached) + if(!m_timerRunning && !storeUncached) return; gatherer.AddForInspection(e); gatherer.GatherAll(); - if(!m_Running && !storeUncached) + if(!m_timerRunning && !storeUncached) return; foreach (UUID assetID in gatherer.GatheredUuids.Keys) @@ -854,13 +859,13 @@ namespace OpenSim.Region.CoreModules.Asset } gatherer.GatheredUuids.Clear(); - if(!m_Running && !storeUncached) + if(!m_timerRunning && !storeUncached) return; if(!storeUncached) Thread.Sleep(50); }); - if(!m_Running && !storeUncached) + if(!m_timerRunning && !storeUncached) break; } @@ -905,16 +910,23 @@ namespace OpenSim.Region.CoreModules.Asset { List outputLines = new List(); - double fileHitRate = (double)m_DiskHits / m_Requests * 100.0; + double invReq = 100.0 / m_Requests; + + double fileHitRate = m_DiskHits * invReq; outputLines.Add( string.Format("File Hit Rate: {0}% for {1} requests", fileHitRate.ToString("0.00"), m_Requests)); if (m_MemoryCacheEnabled) { - double memHitRate = (double)m_MemoryHits / m_Requests * 100.0; + double HitRate = m_MemoryHits * invReq; outputLines.Add( - string.Format("Memory Hit Rate: {0}% for {1} requests", memHitRate.ToString("0.00"), m_Requests)); + string.Format("Memory Hit Rate: {0}% for {1} requests", HitRate.ToString("0.00"), m_Requests)); + + HitRate += fileHitRate; + + outputLines.Add( + string.Format("Total Hit Rate: {0}% for {1} requests", HitRate.ToString("0.00"), m_Requests)); } outputLines.Add( @@ -1019,17 +1031,27 @@ namespace OpenSim.Region.CoreModules.Asset break; case "assets": - con.Output("Ensuring assets are cached for all scenes."); + lock(timerLock) + { + if(m_cleanupRunning) + { + con.OutputFormat("FloatSam assets check already running"); + return; + } + m_cleanupRunning = true; + } + + con.Output("FloatSam Ensuring assets are cached for all scenes."); WorkManager.RunInThread(delegate { bool wasRunning= false; lock(timerLock) { - if(m_Running) + if(m_timerRunning) { m_CacheCleanTimer.Stop(); - m_Running = false; + m_timerRunning = false; wasRunning = true; Thread.Sleep(100); } @@ -1041,8 +1063,9 @@ namespace OpenSim.Region.CoreModules.Asset if(wasRunning) { m_CacheCleanTimer.Start(); - m_Running = true; + m_timerRunning = true; } + m_cleanupRunning = false; } con.OutputFormat("Completed check with {0} assets.", assetReferenceTotal); }, null, "TouchAllSceneAssets"); diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index db8d4db01a..666681211d 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -20,15 +20,20 @@ HitRateDisplay = 100 ; Set to false for no memory cache - MemoryCacheEnabled = false + ; assets can be requested several times in short periods + ; so even a small memory cache is usefull + MemoryCacheEnabled = true ; Set to false for no file cache FileCacheEnabled = true ; How long {in hours} to keep assets cached in memory, .5 == 30 minutes - ; Optimization: for VPS or limited memory system installs set Timeout to .016 (1 minute) - ; increases performance without large memory impact - MemoryCacheTimeout = 2 + ; even a few minutes may mean many assets loaded to memory, if not all. + ; this is good if memory is not a problem. + ; if memory is a problem then a few seconds may actually save same. + ; reducing duplications. + ; see hit rates with console comand: fcache status + MemoryCacheTimeout = .001 // 3.6s ie around 4s (1s resolution) ; How long {in hours} to keep assets cached on disk, .5 == 30 minutes ; Specify 0 if you do not want your disk cache to expire From bf1f4d1384aa087af39b5099f3317f8609283232 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sun, 25 Dec 2016 16:51:54 +0000 Subject: [PATCH 217/305] fix typos (thanks you know who) --- bin/config-include/FlotsamCache.ini.example | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index 666681211d..c0d743093b 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -21,7 +21,7 @@ ; Set to false for no memory cache ; assets can be requested several times in short periods - ; so even a small memory cache is usefull + ; so even a small memory cache is useful MemoryCacheEnabled = true ; Set to false for no file cache @@ -31,9 +31,8 @@ ; even a few minutes may mean many assets loaded to memory, if not all. ; this is good if memory is not a problem. ; if memory is a problem then a few seconds may actually save same. - ; reducing duplications. ; see hit rates with console comand: fcache status - MemoryCacheTimeout = .001 // 3.6s ie around 4s (1s resolution) + MemoryCacheTimeout = .001 ; 3.6s ie around 4s (1s resolution) ; How long {in hours} to keep assets cached on disk, .5 == 30 minutes ; Specify 0 if you do not want your disk cache to expire From 65b4e17a80f5417213ab652ce56d1946d46b2471 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 26 Dec 2016 19:38:13 +0000 Subject: [PATCH 218/305] robust textures add missing returns or redir case --- .../Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs index 518f74ebc8..5f86ed4dbf 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs @@ -80,6 +80,7 @@ namespace OpenSim.Capabilities.Handlers { m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return null; } UUID textureID; @@ -150,6 +151,7 @@ namespace OpenSim.Capabilities.Handlers return true; } WriteTextureData(httpRequest, httpResponse, texture, format); + return true; } else { From 73b2c82427cf25b568705da0920e68effaaf0755 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 28 Dec 2016 12:19:05 +0000 Subject: [PATCH 219/305] adjust camera collision detection checks for new FS --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 463f6c8d0d..5082b9d654 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2821,7 +2821,7 @@ namespace OpenSim.Region.Framework.Scenes m_followCamAuto = false; if(!m_mouseLook) { - if((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f)) + if((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.99f)) { Vector3 camdif = new Vector3(1f, 0f, 0f) * Rotation; float ftmp = camdif.X - CameraAtAxis.X; From 7cf2e812233d767b5a3573b74792aa28d6d91988 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 29 Dec 2016 00:47:02 +0000 Subject: [PATCH 220/305] reinforce gc.collect on region load to also do pending finalizers --- OpenSim/Region/Framework/Scenes/Scene.cs | 11 +++++------ .../Scripting/RegionReadyModule/RegionReadyModule.cs | 4 ++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index e44f11a54e..d7a4ca46aa 100755 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1581,6 +1581,8 @@ namespace OpenSim.Region.Framework.Scenes m_heartbeatThread = null; } + GC.Collect(); + GC.WaitForPendingFinalizers(); GC.Collect(); // tell physics to finish building actor m_sceneGraph.ProcessPhysicsPreSimulation(); @@ -1856,13 +1858,9 @@ namespace OpenSim.Region.Framework.Scenes if (!LoginsEnabled && Frame == 20) { - // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock); - - // In 99.9% of cases it is a bad idea to manually force garbage collection. However, - // this is a rare case where we know we have just went through a long cycle of heap - // allocations, and there is no more work to be done until someone logs in GC.Collect(); - + GC.WaitForPendingFinalizers(); + GC.Collect(); if (!LoginLock) { if (!StartDisabled) @@ -1887,6 +1885,7 @@ namespace OpenSim.Region.Framework.Scenes // LoginLock can currently only be set by a region module implementation. // If somehow this hasn't been done then the quickest way to bugfix is to see the // NullReferenceException + IRegionReadyModule rrm = RequestModuleInterface(); rrm.TriggerRegionReady(this); } diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs index 870c0bbce9..1725eb4f0c 100644 --- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs @@ -214,6 +214,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue; m_scene.LoginLock = false; + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + if (!m_scene.StartDisabled) { m_scene.LoginsEnabled = true; From 1ffcc5981803bd2adb8178daa0e34c353a2ca824 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 29 Dec 2016 03:10:10 +0000 Subject: [PATCH 221/305] gc is also a unwanted cache, so use it. With this, memcache with short expires is no longer needed --- .../CoreModules/Asset/FlotsamAssetCache.cs | 83 ++++++++++++++++--- bin/config-include/FlotsamCache.ini.example | 4 +- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index b6dd5652c7..7bb88b9af6 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -78,6 +78,7 @@ namespace OpenSim.Region.CoreModules.Asset private static ulong m_RequestsForInprogress; private static ulong m_DiskHits; private static ulong m_MemoryHits; + private static ulong m_weakRefHits; #if WAIT_ON_INPROGRESS_REQUESTS private Dictionary m_CurrentlyWriting = new Dictionary(); @@ -92,7 +93,7 @@ namespace OpenSim.Region.CoreModules.Asset private bool m_MemoryCacheEnabled = false; // Expiration is expressed in hours. - private double m_MemoryExpiration = 0.001; + private double m_MemoryExpiration = 0.016; private const double m_DefaultFileExpiration = 48; private TimeSpan m_FileExpiration = TimeSpan.FromHours(m_DefaultFileExpiration); private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(1.0); @@ -107,6 +108,9 @@ namespace OpenSim.Region.CoreModules.Asset private List m_Scenes = new List(); private object timerLock = new object(); + private Dictionary weakAssetReferences = new Dictionary(); + private object weakAssetReferencesLock = new object(); + public FlotsamAssetCache() { m_InvalidChars.AddRange(Path.GetInvalidPathChars()); @@ -255,12 +259,23 @@ namespace OpenSim.Region.CoreModules.Asset } } } + if (m_MemoryCacheEnabled) + m_MemoryCache = new ExpiringCache(); + + lock(weakAssetReferencesLock) + weakAssetReferences = new Dictionary(); } } //////////////////////////////////////////////////////////// // IImprovedAssetCache // + private void UpdateWeakReference(string key, AssetBase asset) + { + WeakReference aref = new WeakReference(asset); + lock(weakAssetReferencesLock) + weakAssetReferences[key] = aref; + } private void UpdateMemoryCache(string key, AssetBase asset) { @@ -327,6 +342,7 @@ namespace OpenSim.Region.CoreModules.Asset if (asset != null) { //m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID); + UpdateWeakReference(asset.ID, asset); if (m_MemoryCacheEnabled) UpdateMemoryCache(asset.ID, asset); @@ -354,6 +370,25 @@ namespace OpenSim.Region.CoreModules.Asset } } + private AssetBase GetFromWeakReference(string id) + { + AssetBase asset = null; + WeakReference aref; + + lock(weakAssetReferencesLock) + { + if (weakAssetReferences.TryGetValue(id, out aref)) + { + asset = aref.Target as AssetBase; + if(asset == null) + weakAssetReferences.Remove(id); + else + m_weakRefHits++; + } + } + return asset; + } + /// /// Try to get an asset from the in-memory cache. /// @@ -477,12 +512,21 @@ namespace OpenSim.Region.CoreModules.Asset m_Requests++; AssetBase asset = null; + asset = GetFromWeakReference(id); - if (m_MemoryCacheEnabled) + if (m_MemoryCacheEnabled && asset == null) + { asset = GetFromMemoryCache(id); + if(asset != null) + UpdateWeakReference(id,asset); + } if (asset == null && m_FileCacheEnabled) + { asset = GetFromFileCache(id); + if(asset != null) + UpdateWeakReference(id,asset); + } if (m_MemoryCacheEnabled && asset != null) UpdateMemoryCache(id, asset); @@ -494,6 +538,12 @@ namespace OpenSim.Region.CoreModules.Asset GenerateCacheHitReport().ForEach(l => m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0}", l)); } + if(asset == null) + { + + + } + return asset; } @@ -553,7 +603,10 @@ namespace OpenSim.Region.CoreModules.Asset } if (m_MemoryCacheEnabled) - m_MemoryCache.Clear(); + m_MemoryCache = new ExpiringCache(); + + lock(weakAssetReferencesLock) + weakAssetReferences = new Dictionary(); } private void CleanupExpiredFiles(object source, ElapsedEventArgs e) @@ -911,28 +964,34 @@ namespace OpenSim.Region.CoreModules.Asset List outputLines = new List(); double invReq = 100.0 / m_Requests; + + double weakHitRate = m_weakRefHits * invReq; + int weakEntries = weakAssetReferences.Count; double fileHitRate = m_DiskHits * invReq; + double TotalHitRate = weakHitRate + fileHitRate; + outputLines.Add( - string.Format("File Hit Rate: {0}% for {1} requests", fileHitRate.ToString("0.00"), m_Requests)); + string.Format("Total requests: {0}", m_Requests)); + outputLines.Add( + string.Format("unCollected Hit Rate: {0}% ({1} entries)", weakHitRate.ToString("0.00"),weakEntries)); + outputLines.Add( + string.Format("File Hit Rate: {0}%", fileHitRate.ToString("0.00"))); if (m_MemoryCacheEnabled) { double HitRate = m_MemoryHits * invReq; - outputLines.Add( - string.Format("Memory Hit Rate: {0}% for {1} requests", HitRate.ToString("0.00"), m_Requests)); + string.Format("Memory Hit Rate: {0}%", HitRate.ToString("0.00"))); - HitRate += fileHitRate; - - outputLines.Add( - string.Format("Total Hit Rate: {0}% for {1} requests", HitRate.ToString("0.00"), m_Requests)); + TotalHitRate += HitRate; } + outputLines.Add( + string.Format("Total Hit Rate: {0}%", TotalHitRate.ToString("0.00"))); outputLines.Add( string.Format( - "Unnecessary requests due to requests for assets that are currently downloading: {0}", - m_RequestsForInprogress)); + "Requests overlap during file writing: {0}", m_RequestsForInprogress)); return outputLines; } diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index c0d743093b..917ea4607c 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -22,7 +22,7 @@ ; Set to false for no memory cache ; assets can be requested several times in short periods ; so even a small memory cache is useful - MemoryCacheEnabled = true + MemoryCacheEnabled = false ; Set to false for no file cache FileCacheEnabled = true @@ -32,7 +32,7 @@ ; this is good if memory is not a problem. ; if memory is a problem then a few seconds may actually save same. ; see hit rates with console comand: fcache status - MemoryCacheTimeout = .001 ; 3.6s ie around 4s (1s resolution) + MemoryCacheTimeout = .016 // one minute ; How long {in hours} to keep assets cached on disk, .5 == 30 minutes ; Specify 0 if you do not want your disk cache to expire From 3a310d77c88f4ddd8e564a98ef7c46665999c3a6 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 29 Dec 2016 03:12:50 +0000 Subject: [PATCH 222/305] forgot one gc.collect wait for finalizers --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index a69b670cd7..55050d9de4 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -621,7 +621,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP GroupsInView.Clear(); if(m_scene.GetNumberOfClients() == 0) - GC.Collect(); + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + } } public void Kick(string message) From c78da183b233f80ba436f677ecbbe32a477bd676 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 29 Dec 2016 03:25:12 +0000 Subject: [PATCH 223/305] expire also from weak references --- OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 7bb88b9af6..e7f498130a 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -580,6 +580,9 @@ namespace OpenSim.Region.CoreModules.Asset if (m_MemoryCacheEnabled) m_MemoryCache.Remove(id); + + lock(weakAssetReferencesLock) + weakAssetReferences.Remove(id); } catch (Exception e) { From feca9fd15385a5e2df27b5a3cc4ea3253be00909 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 29 Dec 2016 11:53:38 +0000 Subject: [PATCH 224/305] Add an option to update the file access time even when an asset is found in cache. When the cache is shared between multiple sims, it is often more efficient to have a single expire job run from cron. Updating file access times is vital to the functioning of such setups. --- .../Region/CoreModules/Asset/FlotsamAssetCache.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index e7f498130a..5400c91d6b 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -110,6 +110,7 @@ namespace OpenSim.Region.CoreModules.Asset private Dictionary weakAssetReferences = new Dictionary(); private object weakAssetReferencesLock = new object(); + private bool m_updateFileTimeOnCacheHit = false; public FlotsamAssetCache() { @@ -156,6 +157,8 @@ namespace OpenSim.Region.CoreModules.Asset m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled); m_MemoryExpiration = assetConfig.GetDouble("MemoryCacheTimeout", m_MemoryExpiration); m_MemoryExpiration *= 3600.0; // config in hours to seconds + + m_updateFileTimeOnCacheHit = assetConfig.GetBoolean("UpdateFileTimeOnCacheHit", m_updateFileTimeOnCacheHit); #if WAIT_ON_INPROGRESS_REQUESTS m_WaitOnInprogressTimeout = assetConfig.GetInt("WaitOnInprogressTimeout", 3000); @@ -513,12 +516,24 @@ namespace OpenSim.Region.CoreModules.Asset AssetBase asset = null; asset = GetFromWeakReference(id); + if (asset != null && m_updateFileTimeOnCacheHit) + { + string filename = GetFileName(id); + UpdateFileLastAccessTime(filename); + } if (m_MemoryCacheEnabled && asset == null) { asset = GetFromMemoryCache(id); if(asset != null) + { UpdateWeakReference(id,asset); + if (m_updateFileTimeOnCacheHit) + { + string filename = GetFileName(id); + UpdateFileLastAccessTime(filename); + } + } } if (asset == null && m_FileCacheEnabled) From f021c64eb060046bff6e91384e1bbca0384b7d61 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 29 Dec 2016 12:34:09 +0000 Subject: [PATCH 225/305] Refactor: Rename IImprovedAssetCache to IAssetCache as the old IAssetCache is long gone. --- OpenSim/Framework/IImprovedAssetCache.cs | 4 ++-- OpenSim/Framework/WearableCacheItem.cs | 4 ++-- .../CoreModules/Agent/TextureSender/J2KDecoderModule.cs | 6 +++--- OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs | 6 +++--- OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs | 6 +++--- OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | 8 ++++---- OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs | 6 +++--- .../Avatar/AvatarFactory/AvatarFactoryModule.cs | 4 ++-- .../CoreModules/Avatar/UserProfiles/UserProfileModule.cs | 4 ++-- .../ServiceConnectorsOut/Asset/HGAssetBroker.cs | 4 ++-- .../Asset/LocalAssetServiceConnector.cs | 4 ++-- .../Asset/RemoteAssetServiceConnector.cs | 4 ++-- .../Region/OptionalModules/Materials/MaterialsModule.cs | 4 ++-- .../Services/Connectors/Asset/AssetServicesConnector.cs | 4 ++-- .../Connectors/SimianGrid/SimianAssetServiceConnector.cs | 4 ++-- 15 files changed, 36 insertions(+), 36 deletions(-) diff --git a/OpenSim/Framework/IImprovedAssetCache.cs b/OpenSim/Framework/IImprovedAssetCache.cs index a853e9015d..855b86b15a 100644 --- a/OpenSim/Framework/IImprovedAssetCache.cs +++ b/OpenSim/Framework/IImprovedAssetCache.cs @@ -29,7 +29,7 @@ using OpenSim.Framework; namespace OpenSim.Framework { - public interface IImprovedAssetCache + public interface IAssetCache { /// /// Cache the specified asset. @@ -61,4 +61,4 @@ namespace OpenSim.Framework /// void Clear(); } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/WearableCacheItem.cs b/OpenSim/Framework/WearableCacheItem.cs index af28abc74c..966a6bc290 100644 --- a/OpenSim/Framework/WearableCacheItem.cs +++ b/OpenSim/Framework/WearableCacheItem.cs @@ -50,7 +50,7 @@ namespace OpenSim.Framework return retitems; } - public static WearableCacheItem[] FromOSD(OSD pInput, IImprovedAssetCache dataCache) + public static WearableCacheItem[] FromOSD(OSD pInput, IAssetCache dataCache) { List ret = new List(); if (pInput.Type == OSDType.Array) @@ -100,7 +100,7 @@ namespace OpenSim.Framework } - public static OSD ToOSD(WearableCacheItem[] pcacheItems, IImprovedAssetCache dataCache) + public static OSD ToOSD(WearableCacheItem[] pcacheItems, IAssetCache dataCache) { OSDArray arr = new OSDArray(); foreach (WearableCacheItem item in pcacheItems) diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs index 47dcbcd3ff..6d1f0c2ab1 100644 --- a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs +++ b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs @@ -57,13 +57,13 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender /// List of client methods to notify of results of decode private readonly Dictionary> m_notifyList = new Dictionary>(); /// Cache that will store decoded JPEG2000 layer boundary data - private IImprovedAssetCache m_cache; - private IImprovedAssetCache Cache + private IAssetCache m_cache; + private IAssetCache Cache { get { if (m_cache == null) - m_cache = m_scene.RequestModuleInterface(); + m_cache = m_scene.RequestModuleInterface(); return m_cache; } diff --git a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs index ebec9d2d74..382b5f2821 100644 --- a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs @@ -91,7 +91,7 @@ namespace OpenSim.Region.CoreModules.Asset /// /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CenomeMemoryAssetCache")] - public class CenomeMemoryAssetCache : IImprovedAssetCache, ISharedRegionModule + public class CenomeMemoryAssetCache : IAssetCache, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -192,7 +192,7 @@ namespace OpenSim.Region.CoreModules.Asset expirationTime); } - #region IImprovedAssetCache Members + #region IAssetCache Members public bool Check(string id) { @@ -308,7 +308,7 @@ namespace OpenSim.Region.CoreModules.Asset public void AddRegion(Scene scene) { if (m_enabled) - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); } /// diff --git a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs index f72074851e..d78b082366 100644 --- a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs @@ -40,7 +40,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Asset { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CoreAssetCache")] - public class CoreAssetCache : ISharedRegionModule, IImprovedAssetCache + public class CoreAssetCache : ISharedRegionModule, IAssetCache { private static readonly ILog m_log = LogManager.GetLogger( @@ -98,7 +98,7 @@ namespace OpenSim.Region.CoreModules.Asset public void AddRegion(Scene scene) { if (m_Enabled) - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); } public void RemoveRegion(Scene scene) @@ -110,7 +110,7 @@ namespace OpenSim.Region.CoreModules.Asset } //////////////////////////////////////////////////////////// - // IImprovedAssetCache + // IAssetCache // public bool Check(string id) { diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 5400c91d6b..fcd42524d2 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -55,7 +55,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Asset { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "FlotsamAssetCache")] - public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService + public class FlotsamAssetCache : ISharedRegionModule, IAssetCache, IAssetService { private static readonly ILog m_log = LogManager.GetLogger( @@ -219,7 +219,7 @@ namespace OpenSim.Region.CoreModules.Asset { if (m_Enabled) { - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); m_Scenes.Add(scene); } } @@ -228,7 +228,7 @@ namespace OpenSim.Region.CoreModules.Asset { if (m_Enabled) { - scene.UnregisterModuleInterface(this); + scene.UnregisterModuleInterface(this); m_Scenes.Remove(scene); lock(timerLock) { @@ -271,7 +271,7 @@ namespace OpenSim.Region.CoreModules.Asset } //////////////////////////////////////////////////////////// - // IImprovedAssetCache + // IAssetCache // private void UpdateWeakReference(string key, AssetBase asset) { diff --git a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs index 5f76ac2c9e..7343f4fbb8 100644 --- a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs @@ -41,7 +41,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Asset { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GlynnTuckerAssetCache")] - public class GlynnTuckerAssetCache : ISharedRegionModule, IImprovedAssetCache + public class GlynnTuckerAssetCache : ISharedRegionModule, IAssetCache { private static readonly ILog m_log = LogManager.GetLogger( @@ -100,7 +100,7 @@ namespace OpenSim.Region.CoreModules.Asset public void AddRegion(Scene scene) { if (m_Enabled) - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); } public void RemoveRegion(Scene scene) @@ -112,7 +112,7 @@ namespace OpenSim.Region.CoreModules.Asset } //////////////////////////////////////////////////////////// - // IImprovedAssetCache + // IAssetCache // public bool Check(string id) diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 41a3f5239e..67256ee685 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -288,7 +288,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (bakedTextures.Count == 0) return false; - IImprovedAssetCache cache = sp.Scene.RequestModuleInterface(); + IAssetCache cache = sp.Scene.RequestModuleInterface(); if(cache == null) return true; // no baked local caching so nothing to do @@ -705,7 +705,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory return 0; int texturesRebaked = 0; -// IImprovedAssetCache cache = m_scene.RequestModuleInterface(); +// IAssetCache cache = m_scene.RequestModuleInterface(); for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) { diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 3f7a8ee7a9..df5265cbe8 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -69,7 +69,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles Dictionary m_classifiedCache = new Dictionary(); Dictionary m_classifiedInterest = new Dictionary(); ExpiringCache m_profilesCache = new ExpiringCache(); - IImprovedAssetCache m_assetCache; + IAssetCache m_assetCache; private JsonRpcRequestManager rpc = new JsonRpcRequestManager(); private bool m_allowUserProfileWebURLs = true; @@ -221,7 +221,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if(!Enabled) return; - m_assetCache = Scene.RequestModuleInterface(); + m_assetCache = Scene.RequestModuleInterface(); } /// diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs index 9eb41f94f6..31d112925f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs @@ -48,7 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private IImprovedAssetCache m_Cache = null; + private IAssetCache m_Cache = null; private IAssetService m_GridService; private IAssetService m_HGService; @@ -176,7 +176,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (m_Cache == null) { - m_Cache = scene.RequestModuleInterface(); + m_Cache = scene.RequestModuleInterface(); if (!(m_Cache is ISharedRegionModule)) m_Cache = null; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs index 5f3445068b..d5d6667504 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs @@ -44,7 +44,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private IImprovedAssetCache m_Cache = null; + private IAssetCache m_Cache = null; private IAssetService m_AssetService; @@ -128,7 +128,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (m_Cache == null) { - m_Cache = scene.RequestModuleInterface(); + m_Cache = scene.RequestModuleInterface(); if (!(m_Cache is ISharedRegionModule)) m_Cache = null; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs index e6eeacfaf6..ff04f9d66e 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs @@ -48,7 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled = false; - private IImprovedAssetCache m_Cache; + private IAssetCache m_Cache; public Type ReplaceableInterface { @@ -111,7 +111,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (m_Cache == null) { - m_Cache = scene.RequestModuleInterface(); + m_Cache = scene.RequestModuleInterface(); // Since we are a shared module and scene data is not // available for every method, the cache must be shared, too diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index 7312bc39a8..b259f52f8f 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.OptionalModules.Materials public Type ReplaceableInterface { get { return null; } } - IImprovedAssetCache m_cache; + IAssetCache m_cache; private Scene m_scene = null; private bool m_enabled = false; private int m_maxMaterialsPerTransaction = 50; @@ -207,7 +207,7 @@ namespace OpenSim.Region.OptionalModules.Materials { if (!m_enabled) return; - m_cache = scene.RequestModuleInterface(); + m_cache = scene.RequestModuleInterface(); ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface(); if (featuresModule != null) featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index a6e8eb424b..b8449d7ce4 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -49,7 +49,7 @@ namespace OpenSim.Services.Connectors const int MAXSENDRETRIESLEN = 30; private string m_ServerURI = String.Empty; - private IImprovedAssetCache m_Cache = null; + private IAssetCache m_Cache = null; private int m_retryCounter; private bool m_inRetries; private List[] m_sendRetries = new List[MAXSENDRETRIESLEN]; @@ -233,7 +233,7 @@ namespace OpenSim.Services.Connectors } } - protected void SetCache(IImprovedAssetCache cache) + protected void SetCache(IAssetCache cache) { m_Cache = cache; } diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs index 9ad4a7a56f..531939f2cc 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -55,7 +55,7 @@ namespace OpenSim.Services.Connectors.SimianGrid private static string ZeroID = UUID.Zero.ToString(); private string m_serverUrl = String.Empty; - private IImprovedAssetCache m_cache; + private IAssetCache m_cache; private bool m_Enabled = false; #region ISharedRegionModule @@ -65,7 +65,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { if (m_cache == null) { - IImprovedAssetCache cache = scene.RequestModuleInterface(); + IAssetCache cache = scene.RequestModuleInterface(); if (cache is ISharedRegionModule) m_cache = cache; } From ec4c258794a9be8c5497b82173759e46e8c63cea Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 29 Dec 2016 12:36:13 +0000 Subject: [PATCH 226/305] Actually rename the file, too --- OpenSim/Framework/{IImprovedAssetCache.cs => IAssetCache.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename OpenSim/Framework/{IImprovedAssetCache.cs => IAssetCache.cs} (100%) diff --git a/OpenSim/Framework/IImprovedAssetCache.cs b/OpenSim/Framework/IAssetCache.cs similarity index 100% rename from OpenSim/Framework/IImprovedAssetCache.cs rename to OpenSim/Framework/IAssetCache.cs From 07b48fd58c343d18b8ce64179e344439070511e8 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 29 Dec 2016 15:47:46 +0000 Subject: [PATCH 227/305] Add negative caching to flotsam cache. Prevents scripts from hammering the asset server --- OpenSim/Framework/IAssetCache.cs | 6 +++ .../CoreModules/Asset/CenomeAssetCache.cs | 5 +++ .../CoreModules/Asset/CoreAssetCache.cs | 5 +++ .../CoreModules/Asset/FlotsamAssetCache.cs | 27 ++++++++++++++ .../Asset/GlynnTuckerAssetCache.cs | 5 +++ .../Asset/AssetServicesConnector.cs | 9 ++++- bin/config-include/FlotsamCache.ini.example | 37 +++++++++++++++++++ 7 files changed, 92 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/IAssetCache.cs b/OpenSim/Framework/IAssetCache.cs index 855b86b15a..8477116403 100644 --- a/OpenSim/Framework/IAssetCache.cs +++ b/OpenSim/Framework/IAssetCache.cs @@ -38,6 +38,12 @@ namespace OpenSim.Framework void Cache(AssetBase asset); /// + /// Cache that the specified asset wasn't found. + /// + /// + /// + void CacheNegative(string id); + /// Get an asset by its id. /// /// diff --git a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs index 382b5f2821..14b0280cd5 100644 --- a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs @@ -221,6 +221,11 @@ namespace OpenSim.Region.CoreModules.Asset } + public void CacheNegative(string id) + { + // We don't do negative caching + } + /// /// Clear asset cache. /// diff --git a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs index d78b082366..82bc5ccebb 100644 --- a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs @@ -124,6 +124,11 @@ namespace OpenSim.Region.CoreModules.Asset m_Cache.Store(asset.ID, asset); } + public void CacheNegative(string id) + { + // We don't do negative caching + } + public AssetBase Get(string id) { return (AssetBase)m_Cache.Get(id); diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index fcd42524d2..84e13a0d9d 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -92,9 +92,15 @@ namespace OpenSim.Region.CoreModules.Asset private ExpiringCache m_MemoryCache; private bool m_MemoryCacheEnabled = false; + private ExpiringCache m_negativeCache; + private bool m_negativeCacheEnabled = true; + private bool m_negativeCacheSliding = false; + // Expiration is expressed in hours. private double m_MemoryExpiration = 0.016; private const double m_DefaultFileExpiration = 48; + // Negative cache is in seconds + private int m_negativeExpiration = 120; private TimeSpan m_FileExpiration = TimeSpan.FromHours(m_DefaultFileExpiration); private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(1.0); @@ -139,6 +145,7 @@ namespace OpenSim.Region.CoreModules.Asset if (name == Name) { m_MemoryCache = new ExpiringCache(); + m_negativeCache = new ExpiringCache(); m_Enabled = true; m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} enabled", this.Name); @@ -158,6 +165,9 @@ namespace OpenSim.Region.CoreModules.Asset m_MemoryExpiration = assetConfig.GetDouble("MemoryCacheTimeout", m_MemoryExpiration); m_MemoryExpiration *= 3600.0; // config in hours to seconds + m_negativeCacheEnabled = assetConfig.GetBoolean("NegativeCacheEnabled", m_negativeCacheEnabled); + m_negativeExpiration = assetConfig.GetInt("NegativeCacheTimeout", m_negativeExpiration); + m_negativeCacheSliding = assetConfig.GetBoolean("NegativeCacheSliding", m_negativeCacheSliding); m_updateFileTimeOnCacheHit = assetConfig.GetBoolean("UpdateFileTimeOnCacheHit", m_updateFileTimeOnCacheHit); #if WAIT_ON_INPROGRESS_REQUESTS @@ -355,6 +365,17 @@ namespace OpenSim.Region.CoreModules.Asset } } + public void CacheNegative(string id) + { + if (m_negativeCacheEnabled) + { + if (m_negativeCacheSliding) + m_negativeCache.AddOrUpdate(id, null, TimeSpan.FromSeconds(m_negativeExpiration)); + else + m_negativeCache.AddOrUpdate(id, null, m_negativeExpiration); + } + } + /// /// Updates the cached file with the current time. /// @@ -514,6 +535,10 @@ namespace OpenSim.Region.CoreModules.Asset { m_Requests++; + object dummy; + if (m_negativeCache.TryGetValue(id, out dummy)) + return null; + AssetBase asset = null; asset = GetFromWeakReference(id); if (asset != null && m_updateFileTimeOnCacheHit) @@ -622,6 +647,8 @@ namespace OpenSim.Region.CoreModules.Asset if (m_MemoryCacheEnabled) m_MemoryCache = new ExpiringCache(); + if (m_negativeCacheEnabled) + m_negativeCache = new ExpiringCache(); lock(weakAssetReferencesLock) weakAssetReferences = new Dictionary(); diff --git a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs index 7343f4fbb8..195bdaa43f 100644 --- a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs @@ -126,6 +126,11 @@ namespace OpenSim.Region.CoreModules.Asset m_Cache.AddOrUpdate(asset.ID, asset); } + public void CacheNegative(string id) + { + // We don't do negative caching + } + public AssetBase Get(string id) { Object asset = null; diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index b8449d7ce4..bdc3befb08 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -260,8 +260,13 @@ namespace OpenSim.Services.Connectors asset = SynchronousRestObjectRequester.MakeRequest("GET", uri, 0, m_Auth); - if (asset != null && m_Cache != null) - m_Cache.Cache(asset); + if (m_Cache != null) + { + if (asset != null) + m_Cache.Cache(asset); + else + m_Cache.CacheNegative(id); + } } return asset; } diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index 917ea4607c..2b5d37e0e0 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -24,6 +24,43 @@ ; so even a small memory cache is useful MemoryCacheEnabled = false + ; If a memory cache hit happens, or the asset is still in memory + ; due to other causes, update the timestamp on the disk file anyway. + ; Don't turn this on unless you share your asset cache between simulators + ; AND use an external process, e.g. cron job, to clean it up. + UpdateFileTimeOnCacheHit = false + + ; Enabling this will cache negative fetches. If an asset is negative-cached + ; it will not be re-requested from the asset server again for a while. + ; Generally, this is a good thing. + ; + ; Regular expiration settings (non-sliding) mean that the asset will be + ; retried after the time has expired. Sliding expiration means that + ; the time the negative cache will keep the asset is refreshed each + ; time a fetch is attempted. Use sliding expiration if you have rogue + ; scripts hammering the asset server with requests for nonexistent + ; assets. + ; + ; There are two cases where negative caching may cause issues: + ; + ; 1 - If an invalid asset is repeatedly requested by a script and that asset is + ; subsequently created, it will not be seen until fcache clear + ; is used. This is a very theoretical scenario since UUID collisions + ; are deemed to be not occuring in practice. + ; This can only become an issue with sliding expiration time. + ; + ; 2 - If the asset service is clustered, an asset may not have propagated + ; to all cluster members when it is first attempted to fetch it. + ; This may theoretically occur with networked vendor systems and + ; would lead to an asset not found message. However, after the + ; expiration time has elapsed, the asset will the be fetchable. + ; + ; The defaults below are suitable for all small to medium installations + ; including grids. + NegativeCacheEnabled = true + NegativeCacheTimeout = 120 + NegativeCacheSliding = false + ; Set to false for no file cache FileCacheEnabled = true From e0b5135010f2292f5c28232e874841b5ed92a559 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 29 Dec 2016 16:29:44 +0000 Subject: [PATCH 228/305] Add a MaxRetries option to the inventory connector. If clustered services are used, another try would go to another server and may succeed. --- .../Inventory/XInventoryServicesConnector.cs | 17 +++++++++++++++-- bin/config-include/GridCommon.ini.example | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs index d80e660553..2ddd7a2f55 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs @@ -54,6 +54,8 @@ namespace OpenSim.Services.Connectors private string m_ServerURI = String.Empty; + private int m_maxRetries = 0; + /// /// Timeout for remote requests. /// @@ -100,6 +102,7 @@ namespace OpenSim.Services.Connectors m_ServerURI = serviceURI; m_requestTimeoutSecs = config.GetInt("RemoteRequestTimeout", m_requestTimeoutSecs); + m_maxRetries = config.GetInt("MaxRetries", m_maxRetries); StatsManager.RegisterStat( new Stat( @@ -700,10 +703,20 @@ namespace OpenSim.Services.Connectors RequestsMade++; - string reply - = SynchronousRestFormsRequester.MakeRequest( + string reply = String.Empty; + int retries = 0; + + do + { + reply = SynchronousRestFormsRequester.MakeRequest( "POST", m_ServerURI + "/xinventory", ServerUtils.BuildQueryString(sendData), m_requestTimeoutSecs, m_Auth); + + if (reply != String.Empty) + break; + + retries++; + } while (retries <= m_maxRetries); Dictionary replyData = ServerUtils.ParseXmlResponse( reply); diff --git a/bin/config-include/GridCommon.ini.example b/bin/config-include/GridCommon.ini.example index 0922cf5a4a..10a5b474d9 100644 --- a/bin/config-include/GridCommon.ini.example +++ b/bin/config-include/GridCommon.ini.example @@ -85,6 +85,7 @@ ; Change this to your grid-wide inventory server ; InventoryServerURI = "${Const|BaseURL}:${Const|PrivatePort}" + ;MaxRetries = 0 [GridInfo] ; From aee3f273f099c16a770ad4f3f4c9f1ee40227aef Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Thu, 29 Dec 2016 23:20:33 +0100 Subject: [PATCH 229/305] Serving robots.txt from bin Idea of solution for http://opensimulator.org/mantis/view.php?id=7392 Signed-off-by: Mandarinka Tasty Signed-off-by: Melanie Thielker --- OpenSim/Region/Application/OpenSim.cs | 1 + OpenSim/Region/Application/OpenSimBase.cs | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 3cb999bee5..d9fdcde732 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -206,6 +206,7 @@ namespace OpenSim MainServer.Instance.AddStreamHandler(new OpenSim.XSimStatusHandler(this)); if (userStatsURI != String.Empty) MainServer.Instance.AddStreamHandler(new OpenSim.UXSimStatusHandler(this)); + MainServer.Instance.AddStreamHandler(new OpenSim.SimRobotsHandler()); if (managedStatsURI != String.Empty) { diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 52ded3d055..8499a90acd 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -876,6 +876,26 @@ namespace OpenSim } } + /// + /// handler to supply serving http://domainname:port/robots.txt + /// + public class SimRobotsHandler : BaseStreamHandler + { + public SimRobotsHandler() : base("GET", "/robots.txt", "SimRobots.txt", "Simulator Robots.txt") {} + + protected override byte[] ProcessRequest(string path, Stream request, + IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + string robots = "# go away\nUser-agent: *\nDisallow: /\n"; + return Util.UTF8.GetBytes(robots); + } + + public override string ContentType + { + get { return "text/plain"; } + } + } + #endregion /// From 2836f16ae13fa645aeb6e712a3c4f73771788098 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 30 Dec 2016 02:14:16 +0000 Subject: [PATCH 230/305] fix typos --- bin/config-include/FlotsamCache.ini.example | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index 2b5d37e0e0..4f16943658 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -53,7 +53,7 @@ ; to all cluster members when it is first attempted to fetch it. ; This may theoretically occur with networked vendor systems and ; would lead to an asset not found message. However, after the - ; expiration time has elapsed, the asset will the be fetchable. + ; expiration time has elapsed, the asset will then be fetchable. ; ; The defaults below are suitable for all small to medium installations ; including grids. @@ -69,13 +69,13 @@ ; this is good if memory is not a problem. ; if memory is a problem then a few seconds may actually save same. ; see hit rates with console comand: fcache status - MemoryCacheTimeout = .016 // one minute + MemoryCacheTimeout = .016 ; one minute ; How long {in hours} to keep assets cached on disk, .5 == 30 minutes ; Specify 0 if you do not want your disk cache to expire FileCacheTimeout = 48 - ; How often {in hours} should the disk be checked for expired filed + ; How often {in hours} should the disk be checked for expired files ; Specify 0 to disable expiration checking FileCleanupTimer = 0.0 ; disabled From ee485187db20de24718b394d9ec6f503c578e491 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 30 Dec 2016 04:57:34 +0000 Subject: [PATCH 231/305] remove a gc.collect that isn't very usefull --- OpenSim/Region/PhysicsModules/Ode/OdeScene.cs | 4671 +++++++---------- 1 file changed, 1961 insertions(+), 2710 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs index ed2aad424e..410463c77a 100644 --- a/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs +++ b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs @@ -25,52 +25,54 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// changes for varsize regions -// note that raycasts need to have limited range -// (even in normal regions) -// or application thread stack may just blowup -// see RayCast(ODERayCastRequest req) +// Revision 2011/12/13 by Ubit Umarov +//#define SPAM using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Threading; +using System.IO; +using System.Diagnostics; using log4net; using Nini.Config; using Mono.Addins; -using OpenMetaverse; +using OdeAPI; using OpenSim.Framework; -using OpenSim.Region.PhysicsModules.SharedBase; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenMetaverse; -namespace OpenSim.Region.PhysicsModule.ODE +namespace OpenSim.Region.PhysicsModule.ubOde { - public enum StatusIndicators : int - { - Generic = 0, - Start = 1, - End = 2 - } + // colision flags of things others can colide with + // rays, sensors, probes removed since can't be colided with + // The top space where things are placed provided further selection + // ie physical are in active space nonphysical in static + // this should be exclusive as possible [Flags] - public enum CollisionCategories : int + public enum CollisionCategories : uint { Disabled = 0, - Geom = 0x00000001, - Body = 0x00000002, - Space = 0x00000004, - Character = 0x00000008, - Land = 0x00000010, - Water = 0x00000020, - Wind = 0x00000040, - Sensor = 0x00000080, - Selected = 0x00000100 + //by 'things' types + Space = 0x01, + Geom = 0x02, // aka prim/part + Character = 0x04, + Land = 0x08, + Water = 0x010, + + // by state + Phantom = 0x01000, + VolumeDtc = 0x02000, + Selected = 0x04000, + NoShape = 0x08000, + + + All = 0xffffffff } /// @@ -91,836 +93,579 @@ namespace OpenSim.Region.PhysicsModule.ODE /// Plastic = 5, /// - Rubber = 6 + Rubber = 6, + + light = 7 // compatibility with old viewers + } + + public enum changes : int + { + Add = 0, // arg null. finishs the prim creation. should be used internally only ( to remove later ?) + Remove, + Link, // arg AuroraODEPrim new parent prim or null to delink. Makes the prim part of a object with prim parent as root + // or removes from a object if arg is null + DeLink, + Position, // arg Vector3 new position in world coords. Changes prim position. Prim must know if it is root or child + Orientation, // arg Quaternion new orientation in world coords. Changes prim position. Prim must know it it is root or child + PosOffset, // not in use + // arg Vector3 new position in local coords. Changes prim position in object + OriOffset, // not in use + // arg Vector3 new position in local coords. Changes prim position in object + Velocity, + TargetVelocity, + AngVelocity, + Acceleration, + Force, + Torque, + Momentum, + + AddForce, + AddAngForce, + AngLock, + + Buoyancy, + + PIDTarget, + PIDTau, + PIDActive, + + PIDHoverHeight, + PIDHoverType, + PIDHoverTau, + PIDHoverActive, + + Size, + AvatarSize, + Shape, + PhysRepData, + AddPhysRep, + + CollidesWater, + VolumeDtc, + + Physical, + Phantom, + Selected, + disabled, + building, + + VehicleType, + VehicleFloatParam, + VehicleVectorParam, + VehicleRotationParam, + VehicleFlags, + SetVehicle, + + Null //keep this last used do dim the methods array. does nothing but pulsing the prim } - public class OdeScene : PhysicsScene + public struct ODEchangeitem { - private readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString()); + public PhysicsActor actor; + public OdeCharacter character; + public changes what; + public Object arg; + } - // private Dictionary m_storedCollisions = new Dictionary(); + public class ODEScene : PhysicsScene + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - /// - /// Provide a sync object so that only one thread calls d.Collide() at a time across all OdeScene instances. - /// - /// - /// With ODE as of r1755 (though also tested on r1860), only one thread can call d.Collide() at a - /// time, even where physics objects are in entirely different ODE worlds. This is because generating contacts - /// uses a static cache at the ODE level. - /// - /// Without locking, simulators running multiple regions will eventually crash with a native stack trace similar - /// to - /// - /// mono() [0x489171] - /// mono() [0x4d154f] - /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f6ded592c60] - /// .../opensim/bin/libode-x86_64.so(_ZN6Opcode11OBBCollider8_CollideEPKNS_14AABBNoLeafNodeE+0xd7a) [0x7f6dd822628a] - /// - /// ODE provides an experimental option to cache in thread local storage but compiling ODE with this option - /// causes OpenSimulator to immediately crash with a native stack trace similar to - /// - /// mono() [0x489171] - /// mono() [0x4d154f] - /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f03c9849c60] - /// .../opensim/bin/libode-x86_64.so(_Z12dCollideCCTLP6dxGeomS0_iP12dContactGeomi+0x92) [0x7f03b44bcf82] - /// - internal static Object UniversalColliderSyncObject = new Object(); - internal static Object SimulationLock = new Object(); + public bool m_OSOdeLib = false; + public Scene m_frameWorkScene = null; + +// private int threadid = 0; + +// const d.ContactFlags comumContactFlags = d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM |d.ContactFlags.Approx1 | d.ContactFlags.Bounce; + + const d.ContactFlags comumContactFlags = d.ContactFlags.Bounce | d.ContactFlags.Approx1 | d.ContactFlags.Slip1 | d.ContactFlags.Slip2; + const float comumContactERP = 0.75f; + const float comumContactCFM = 0.0001f; + const float comumContactSLIP = 0f; - /// - /// Is stats collecting enabled for this ODE scene? - /// - public bool CollectStats { get; set; } + float frictionMovementMult = 0.8f; - /// - /// Statistics for this scene. - /// - private Dictionary m_stats = new Dictionary(); + float TerrainBounce = 0.1f; + float TerrainFriction = 0.3f; - /// - /// Stat name for total number of avatars in this ODE scene. - /// - public const string ODETotalAvatarsStatName = "ODETotalAvatars"; - - /// - /// Stat name for total number of prims in this ODE scene. - /// - public const string ODETotalPrimsStatName = "ODETotalPrims"; - - /// - /// Stat name for total number of prims with active physics in this ODE scene. - /// - public const string ODEActivePrimsStatName = "ODEActivePrims"; - - /// - /// Stat name for the total time spent in ODE frame processing. - /// - /// - /// A sanity check for the main scene loop physics time. - /// - public const string ODETotalFrameMsStatName = "ODETotalFrameMS"; - - /// - /// Stat name for time spent processing avatar taints per frame - /// - public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS"; - - /// - /// Stat name for time spent processing prim taints per frame - /// - public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS"; - - /// - /// Stat name for time spent calculating avatar forces per frame. - /// - public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS"; - - /// - /// Stat name for time spent calculating prim forces per frame - /// - public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS"; - - /// - /// Stat name for time spent fulfilling raycasting requests per frame - /// - public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS"; - - /// - /// Stat name for time spent in native code that actually steps through the simulation. - /// - public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS"; - - /// - /// Stat name for the number of milliseconds that ODE spends in native space collision code. - /// - public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS"; - - /// - /// Stat name for milliseconds that ODE spends in native geom collision code. - /// - public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS"; - - /// - /// Time spent in collision processing that is not spent in native space or geom collision code. - /// - public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS"; - - /// - /// Stat name for time spent notifying listeners of collisions - /// - public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS"; - - /// - /// Stat name for milliseconds spent updating avatar position and velocity - /// - public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS"; - - /// - /// Stat name for the milliseconds spent updating prim position and velocity - /// - public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS"; - - /// - /// Stat name for avatar collisions with another entity. - /// - public const string ODEAvatarContactsStatsName = "ODEAvatarContacts"; - - /// - /// Stat name for prim collisions with another entity. - /// - public const string ODEPrimContactsStatName = "ODEPrimContacts"; - - /// - /// Used to hold tick numbers for stat collection purposes. - /// - private int m_nativeCollisionStartTick; - - /// - /// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback. - /// - private bool m_inCollisionTiming; - - /// - /// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object - /// collisions occured using the _perloopcontact if stats collection is enabled. - /// - private int m_tempAvatarCollisionsThisFrame; - - /// - /// Used in calculating physics frame time dilation - /// - private int tickCountFrameRun; - - /// - /// Used in calculating physics frame time dilation - /// - private int latertickcount; - - private Random fluidRandomizer = new Random(Environment.TickCount); + public float AvatarFriction = 0;// 0.9f * 0.5f; + // this netx dimensions are only relevant for terrain partition (mega regions) + // WorldExtents below has the simulation dimensions + // they should be identical except on mega regions private uint m_regionWidth = Constants.RegionSize; private uint m_regionHeight = Constants.RegionSize; - private float ODE_STEPSIZE = 0.0178f; - private float metersInSpace = 29.9f; + public float ODE_STEPSIZE = 0.020f; + public float HalfOdeStep = 0.01f; + public int odetimestepMS = 20; // rounded + private float metersInSpace = 25.6f; private float m_timeDilation = 1.0f; + private DateTime m_lastframe; + private DateTime m_lastMeshExpire; + public float gravityx = 0f; public float gravityy = 0f; public float gravityz = -9.8f; - public float AvatarTerminalVelocity { get; set; } - - private float contactsurfacelayer = 0.001f; - - private int HashspaceLow = -5; - private int HashspaceHigh = 12; - private float waterlevel = 0f; private int framecount = 0; - //private int m_returncollisions = 10; - - private IntPtr contactgroup; - -// internal IntPtr WaterGeom; - - private float nmTerrainContactFriction = 255.0f; - private float nmTerrainContactBounce = 0.1f; - private float nmTerrainContactERP = 0.1025f; - - private float mTerrainContactFriction = 75f; - private float mTerrainContactBounce = 0.1f; - private float mTerrainContactERP = 0.05025f; - - private float nmAvatarObjectContactFriction = 250f; - private float nmAvatarObjectContactBounce = 0.1f; - - private float mAvatarObjectContactFriction = 75f; - private float mAvatarObjectContactBounce = 0.1f; - - private float avPIDD = 3200f; - private float avPIDP = 1400f; - private float avCapRadius = 0.37f; - private float avStandupTensor = 2000000f; - - /// - /// true = old compatibility mode with leaning capsule; false = new corrected mode - /// - /// - /// Even when set to false, the capsule still tilts but this is done in a different way. - /// - public bool IsAvCapsuleTilted { get; private set; } private float avDensity = 80f; private float avMovementDivisorWalk = 1.3f; private float avMovementDivisorRun = 0.8f; private float minimumGroundFlightOffset = 3f; public float maximumMassObject = 10000.01f; + public float geomDefaultDensity = 10.0f; - public bool meshSculptedPrim = true; - public bool forceSimplePrimMeshing = false; - - public float meshSculptLOD = 32; - public float MeshSculptphysicalLOD = 16; - - public float geomDefaultDensity = 10.000006836f; - - public int geomContactPointsStartthrottle = 3; - public int geomUpdatesPerThrottledUpdate = 15; - private const int avatarExpectedContacts = 3; + public float maximumAngularVelocity = 12.0f; // default 12rad/s + public float maxAngVelocitySQ = 144f; // squared value public float bodyPIDD = 35f; public float bodyPIDG = 25; - public int bodyFramesAutoDisable = 20; - - private bool m_filterCollisions = true; + public int bodyFramesAutoDisable = 5; private d.NearCallback nearCallback; - public d.TriCallback triCallback; - public d.TriArrayCallback triArrayCallback; + + private Dictionary _prims = new Dictionary(); + private HashSet _characters = new HashSet(); + private HashSet _activeprims = new HashSet(); + private HashSet _activegroups = new HashSet(); + + public OpenSim.Framework.LocklessQueue ChangesQueue = new OpenSim.Framework.LocklessQueue(); /// - /// Avatars in the physics scene. + /// A list of actors that should receive collision events. /// - 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(); - - /// - /// Prims that the simulator has created/deleted/updated and so need updating in ODE. - /// - private readonly HashSet _taintedPrims = 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(); - - /// - /// A dictionary of actors that should receive collision events. - /// - private readonly Dictionary m_collisionEventActors = new Dictionary(); - - /// - /// A dictionary of collision event changes that are waiting to be processed. - /// - private readonly Dictionary m_collisionEventActorsChanges = new Dictionary(); - - /// - /// Maps a unique geometry id (a memory location) to a physics actor name. - /// - /// - /// 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(); - - /// - /// Maps a unique geometry id (a memory location) to a physics actor. - /// - /// - /// Only actors participating in collisions have geometries. - /// + private List _collisionEventPrim = new List(); + private List _collisionEventPrimRemove = new List(); + + private HashSet _badCharacter = new HashSet(); 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 float contactsurfacelayer = 0.002f; - private bool m_NINJA_physics_joints_enabled = false; - //private Dictionary jointpart_name_map = new Dictionary(); - private readonly Dictionary> joints_connecting_actor = new Dictionary>(); - private d.ContactGeom[] contacts; + private int contactsPerCollision = 80; + internal IntPtr ContactgeomsArray = IntPtr.Zero; + private IntPtr GlobalContactsArray = IntPtr.Zero; + private d.Contact SharedTmpcontact = new d.Contact(); - /// - /// 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(); + const int maxContactsbeforedeath = 6000; + private volatile int m_global_contactcount = 0; - /// - /// can lock for longer. accessed only by OdeScene. - /// - private readonly List pendingJoints = new List(); + private IntPtr contactgroup; - /// - /// can lock for longer. accessed only by OdeScene. - /// - private readonly List activeJoints = new List(); + public ContactData[] m_materialContactsData = new ContactData[8]; - /// - /// 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(); - private readonly DoubleDictionary RegionTerrain = new DoubleDictionary(); - private readonly Dictionary TerrainHeightFieldHeights = new Dictionary(); - - private d.Contact contact; - private d.Contact TerrainContact; - private d.Contact AvatarMovementprimContact; - private d.Contact AvatarMovementTerrainContact; - private d.Contact WaterContact; - private d.Contact[,] m_materialContacts; - - private int m_physicsiterations = 10; + private IntPtr TerrainGeom; + private float[] TerrainHeightFieldHeight; + private GCHandle TerrainHeightFieldHeightsHandler = new GCHandle(); + + private int m_physicsiterations = 15; private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag - private readonly PhysicsActor PANull = new NullPhysicsActor(); +// private PhysicsActor PANull = new NullPhysicsActor(); private float step_time = 0.0f; + public IntPtr world; - private uint obj2LocalID = 0; - private OdeCharacter cc1; - private OdePrim cp1; - private OdeCharacter cc2; - private OdePrim cp2; - private int p1ExpectedPoints = 0; - private int p2ExpectedPoints = 0; - public IntPtr space; + // split the spaces acording to contents type + // ActiveSpace contains characters and active prims + // StaticSpace contains land and other that is mostly static in enviroment + // this can contain subspaces, like the grid in staticspace + // as now space only contains this 2 top spaces - // split static geometry collision handling into spaces of 30 meters - public IntPtr[,] staticPrimspace; + public IntPtr TopSpace; // the global space + public IntPtr ActiveSpace; // space for active prims + public IntPtr CharsSpace; // space for active prims + public IntPtr StaticSpace; // space for the static things around + public IntPtr GroundSpace; // space for ground - /// - /// Used to lock the entire physics scene. Locked during the main part of Simulate() - /// - internal Object OdeLock = new Object(); + // some speedup variables + private int spaceGridMaxX; + private int spaceGridMaxY; + private float spacesPerMeterX; + private float spacesPerMeterY; - private bool _worldInitialized = false; + // split static geometry collision into a grid as before + private IntPtr[,] staticPrimspace; + private IntPtr[] staticPrimspaceOffRegion; + + public Object OdeLock; + public static Object SimulationLock; public IMesher mesher; - private IConfigSource m_config; + public IConfigSource m_config; public bool physics_logging = false; public int physics_logging_interval = 0; public bool physics_logging_append_existing_logfile = false; - private bool avplanted = false; - private bool av_av_collisions_off = false; - - public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); - public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); - - private volatile int m_global_contactcount = 0; - - private Vector3 m_worldOffset = Vector3.Zero; public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); - private PhysicsScene m_parentScene = null; - - float spacesPerMeterX; - float spacesPerMeterY; - int spaceGridMaxX; - int spaceGridMaxY; private ODERayCastRequestManager m_rayCastManager; - - public Scene m_frameWorkScene = null; + public ODEMeshWorker m_meshWorker; + + /* maybe needed if ode uses tls + private void checkThread() + { + + int th = Thread.CurrentThread.ManagedThreadId; + if(th != threadid) + { + threadid = th; + d.AllocateODEDataForThread(~0U); + } + } + */ + + IConfig physicsconfig = null; + + public ODEScene(Scene pscene, IConfigSource psourceconfig, string pname, string pversion, bool pOSOdeLib) + { + OdeLock = new Object(); - public OdeScene(Scene pscene, IConfigSource psourceconfig, string pname, string pversion) - { - m_config = psourceconfig; - m_frameWorkScene = pscene; - EngineType = pname; PhysicsSceneName = EngineType + "/" + pscene.RegionInfo.RegionName; EngineName = pname + " " + pversion; + m_config = psourceconfig; + m_OSOdeLib = pOSOdeLib; - pscene.RegisterModuleInterface(this); - Vector3 extent = new Vector3(pscene.RegionInfo.RegionSizeX, pscene.RegionInfo.RegionSizeY, pscene.RegionInfo.RegionSizeZ); - Initialise(extent); - InitialiseFromConfig(m_config); +// m_OSOdeLib = false; //debug - // This may not be that good since terrain may not be avaiable at this point - base.Initialise(pscene.PhysicsRequestAsset, - (pscene.Heightmap != null ? pscene.Heightmap.GetFloatsSerialised() : new float[(int)(extent.X * extent.Y)]), - (float)pscene.RegionInfo.RegionSettings.WaterHeight); + m_frameWorkScene = pscene; + m_frameWorkScene.RegisterModuleInterface(this); + + Initialization(); + + base.Initialise(m_frameWorkScene.PhysicsRequestAsset, + (m_frameWorkScene.Heightmap != null ? m_frameWorkScene.Heightmap.GetFloatsSerialised() : new float[m_frameWorkScene.RegionInfo.RegionSizeX * m_frameWorkScene.RegionInfo.RegionSizeY]), + (float)m_frameWorkScene.RegionInfo.RegionSettings.WaterHeight); } - public void RegionLoaded() + public void RegionLoaded() { mesher = m_frameWorkScene.RequestModuleInterface(); if (mesher == null) - m_log.WarnFormat("[ODE SCENE]: No mesher in {0}. Things will not work well.", PhysicsSceneName); - - m_frameWorkScene.PhysicsEnabled = true; + { + m_log.ErrorFormat("[ubOde] No mesher. module disabled"); + return; + } + + m_meshWorker = new ODEMeshWorker(this, m_log, mesher, physicsconfig); + m_frameWorkScene.PhysicsEnabled = true; } - /// /// Initiailizes the scene /// Sets many properties that ODE requires to be stable /// These settings need to be tweaked 'exactly' right or weird stuff happens. /// - private void Initialise(Vector3 regionExtent) + private void Initialization() { - WorldExtents.X = regionExtent.X; - m_regionWidth = (uint)regionExtent.X; - WorldExtents.Y = regionExtent.Y; - m_regionHeight = (uint)regionExtent.Y; - + d.AllocateODEDataForThread(~0U); + + SimulationLock = new Object(); + nearCallback = near; + m_rayCastManager = new ODERayCastRequestManager(this); - // Create the world and the first space - world = d.WorldCreate(); - space = d.HashSpaceCreate(IntPtr.Zero); + WorldExtents.X = m_frameWorkScene.RegionInfo.RegionSizeX; + m_regionWidth = (uint)WorldExtents.X; + WorldExtents.Y = m_frameWorkScene.RegionInfo.RegionSizeY; + m_regionHeight = (uint)WorldExtents.Y; - contactgroup = d.JointGroupCreate(0); + lock (OdeLock) + { + // Create the world and the first space + try + { + world = d.WorldCreate(); + TopSpace = d.HashSpaceCreate(IntPtr.Zero); - d.WorldSetAutoDisableFlag(world, false); - } + // now the major subspaces + ActiveSpace = d.HashSpaceCreate(TopSpace); + CharsSpace = d.HashSpaceCreate(TopSpace); + StaticSpace = d.HashSpaceCreate(TopSpace); + GroundSpace = d.HashSpaceCreate(TopSpace); + } + catch + { + // i must RtC#FM + // i did! + } + + d.HashSpaceSetLevels(TopSpace, -5, 12); + d.HashSpaceSetLevels(ActiveSpace, -5, 10); + d.HashSpaceSetLevels(CharsSpace, -4, 3); + d.HashSpaceSetLevels(StaticSpace, -5, 12); + d.HashSpaceSetLevels(GroundSpace, 0, 8); + + // demote to second level + d.SpaceSetSublevel(ActiveSpace, 1); + d.SpaceSetSublevel(CharsSpace, 1); + d.SpaceSetSublevel(StaticSpace, 1); + d.SpaceSetSublevel(GroundSpace, 1); + + d.GeomSetCategoryBits(ActiveSpace, (uint)(CollisionCategories.Space | + CollisionCategories.Geom | + CollisionCategories.Character | + CollisionCategories.Phantom | + CollisionCategories.VolumeDtc + )); + d.GeomSetCollideBits(ActiveSpace, (uint)(CollisionCategories.Space | + CollisionCategories.Geom | + CollisionCategories.Character | + CollisionCategories.Phantom | + CollisionCategories.VolumeDtc + )); + d.GeomSetCategoryBits(CharsSpace, (uint)(CollisionCategories.Space | + CollisionCategories.Geom | + CollisionCategories.Character | + CollisionCategories.Phantom | + CollisionCategories.VolumeDtc + )); + d.GeomSetCollideBits(CharsSpace, 0); + + d.GeomSetCategoryBits(StaticSpace, (uint)(CollisionCategories.Space | + CollisionCategories.Geom | + // CollisionCategories.Land | + // CollisionCategories.Water | + CollisionCategories.Phantom | + CollisionCategories.VolumeDtc + )); + d.GeomSetCollideBits(StaticSpace, 0); + + d.GeomSetCategoryBits(GroundSpace, (uint)(CollisionCategories.Land)); + d.GeomSetCollideBits(GroundSpace, 0); + + contactgroup = d.JointGroupCreate(maxContactsbeforedeath + 1); + //contactgroup + + d.WorldSetAutoDisableFlag(world, false); + } + + + // checkThread(); - // Initialize from configs - private void InitialiseFromConfig(IConfigSource config) - { - InitializeExtraStats(); - m_config = config; // Defaults - avPIDD = 2200.0f; - avPIDP = 900.0f; - avStandupTensor = 550000f; - int contactsPerCollision = 80; + physicsconfig = null; + if (m_config != null) { - IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; + physicsconfig = m_config.Configs["ODEPhysicsSettings"]; if (physicsconfig != null) { - CollectStats = physicsconfig.GetBoolean("collect_stats", false); + gravityx = physicsconfig.GetFloat("world_gravityx", gravityx); + gravityy = physicsconfig.GetFloat("world_gravityy", gravityy); + gravityz = physicsconfig.GetFloat("world_gravityz", gravityz); - gravityx = physicsconfig.GetFloat("world_gravityx", 0f); - gravityy = physicsconfig.GetFloat("world_gravityy", 0f); - gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f); + metersInSpace = physicsconfig.GetFloat("meters_in_small_space", metersInSpace); - float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 54f); - AvatarTerminalVelocity = Util.Clamp(avatarTerminalVelocity, 0, 255f); - if (AvatarTerminalVelocity != avatarTerminalVelocity) - { - m_log.WarnFormat( - "[ODE SCENE]: avatar_terminal_velocity of {0} is invalid. Clamping to {1}", - avatarTerminalVelocity, AvatarTerminalVelocity); - } - - HashspaceLow = physicsconfig.GetInt("world_hashspace_level_low", -5); - HashspaceHigh = physicsconfig.GetInt("world_hashspace_level_high", 12); - - metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f); - - contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f); - - nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f); - nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f); - nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f); - - mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f); - mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f); - mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f); - - nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f); - nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f); - - mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f); - mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f); + // contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", contactsurfacelayer); ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE); - m_physicsiterations = physicsconfig.GetInt("world_solver_iterations", 10); - avDensity = physicsconfig.GetFloat("av_density", 80f); -// avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f); - avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); - avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); - avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); - avplanted = physicsconfig.GetBoolean("av_planted", false); - av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false); + avDensity = physicsconfig.GetFloat("av_density", avDensity); + avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", avMovementDivisorWalk); + avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", avMovementDivisorRun); - IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); + contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", contactsPerCollision); - contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); - - geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5); - geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); - - geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f); - bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20); - - bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f); - bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f); - - forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing); - meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true); - meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f); - MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); - m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); - - avPIDD = physicsconfig.GetFloat("av_pid_derivative", 2200.0f); - avPIDP = physicsconfig.GetFloat("av_pid_proportional", 900.0f); - avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor", 550000f); + geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", geomDefaultDensity); + bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", bodyFramesAutoDisable); physics_logging = physicsconfig.GetBoolean("physics_logging", false); physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0); physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false); -// m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false); - minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f); - maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f); + minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", minimumGroundFlightOffset); + maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", maximumMassObject); + + avDensity *= 3f / 80f; // scale other engines density option to this } } - contacts = new d.ContactGeom[contactsPerCollision]; + float heartbeat = 1/m_frameWorkScene.FrameTime; + maximumAngularVelocity = 0.49f * heartbeat *(float)Math.PI; + maxAngVelocitySQ = maximumAngularVelocity * maximumAngularVelocity; + + d.WorldSetCFM(world, comumContactCFM); + d.WorldSetERP(world, comumContactERP); + + d.WorldSetGravity(world, gravityx, gravityy, gravityz); + + d.WorldSetLinearDamping(world, 0.002f); + d.WorldSetAngularDamping(world, 0.002f); + d.WorldSetAngularDampingThreshold(world, 0f); + d.WorldSetLinearDampingThreshold(world, 0f); + d.WorldSetMaxAngularSpeed(world, maximumAngularVelocity); + + d.WorldSetQuickStepNumIterations(world, m_physicsiterations); + + d.WorldSetContactSurfaceLayer(world, contactsurfacelayer); + d.WorldSetContactMaxCorrectingVel(world, 60.0f); + + HalfOdeStep = ODE_STEPSIZE * 0.5f; + odetimestepMS = (int)(1000.0f * ODE_STEPSIZE + 0.5f); + + ContactgeomsArray = Marshal.AllocHGlobal(contactsPerCollision * d.ContactGeom.unmanagedSizeOf); + GlobalContactsArray = Marshal.AllocHGlobal((maxContactsbeforedeath + 100) * d.Contact.unmanagedSizeOf); + + SharedTmpcontact.geom.g1 = IntPtr.Zero; + SharedTmpcontact.geom.g2 = IntPtr.Zero; + + SharedTmpcontact.geom.side1 = -1; + SharedTmpcontact.geom.side2 = -1; + + SharedTmpcontact.surface.mode = comumContactFlags; + SharedTmpcontact.surface.mu = 0; + SharedTmpcontact.surface.bounce = 0; + SharedTmpcontact.surface.soft_cfm = comumContactCFM; + SharedTmpcontact.surface.soft_erp = comumContactERP; + SharedTmpcontact.surface.slip1 = comumContactSLIP; + SharedTmpcontact.surface.slip2 = comumContactSLIP; + + m_materialContactsData[(int)Material.Stone].mu = 0.8f; + m_materialContactsData[(int)Material.Stone].bounce = 0.4f; + + m_materialContactsData[(int)Material.Metal].mu = 0.3f; + m_materialContactsData[(int)Material.Metal].bounce = 0.4f; + + m_materialContactsData[(int)Material.Glass].mu = 0.2f; + m_materialContactsData[(int)Material.Glass].bounce = 0.7f; + + m_materialContactsData[(int)Material.Wood].mu = 0.6f; + m_materialContactsData[(int)Material.Wood].bounce = 0.5f; + + m_materialContactsData[(int)Material.Flesh].mu = 0.9f; + m_materialContactsData[(int)Material.Flesh].bounce = 0.3f; + + m_materialContactsData[(int)Material.Plastic].mu = 0.4f; + m_materialContactsData[(int)Material.Plastic].bounce = 0.7f; + + m_materialContactsData[(int)Material.Rubber].mu = 0.9f; + m_materialContactsData[(int)Material.Rubber].bounce = 0.95f; + + m_materialContactsData[(int)Material.light].mu = 0.0f; + m_materialContactsData[(int)Material.light].bounce = 0.0f; + spacesPerMeterX = 1.0f / metersInSpace; - spacesPerMeterY = 1.0f / metersInSpace; - + spacesPerMeterY = spacesPerMeterX; spaceGridMaxX = (int)(WorldExtents.X * spacesPerMeterX); spaceGridMaxY = (int)(WorldExtents.Y * spacesPerMeterY); - // note: limit number of spaces if (spaceGridMaxX > 24) { spaceGridMaxX = 24; - spacesPerMeterX = spaceGridMaxX / WorldExtents.X; + spacesPerMeterX = spaceGridMaxX / WorldExtents.X; } + if (spaceGridMaxY > 24) { spaceGridMaxY = 24; spacesPerMeterY = spaceGridMaxY / WorldExtents.Y; } - staticPrimspace = new IntPtr[spaceGridMaxX, spaceGridMaxY]; + staticPrimspace = new IntPtr[spaceGridMaxX, spaceGridMaxY]; - // make this index limits + // create all spaces now + int i, j; + IntPtr newspace; + + for (i = 0; i < spaceGridMaxX; i++) + for (j = 0; j < spaceGridMaxY; j++) + { + newspace = d.HashSpaceCreate(StaticSpace); + d.GeomSetCategoryBits(newspace, (int)CollisionCategories.Space); + waitForSpaceUnlock(newspace); + d.SpaceSetSublevel(newspace, 2); + d.HashSpaceSetLevels(newspace, -2, 8); + d.GeomSetCategoryBits(newspace, (uint)(CollisionCategories.Space | + CollisionCategories.Geom | + CollisionCategories.Land | + CollisionCategories.Water | + CollisionCategories.Phantom | + CollisionCategories.VolumeDtc + )); + d.GeomSetCollideBits(newspace, 0); + + staticPrimspace[i, j] = newspace; + } + + // let this now be index limit spaceGridMaxX--; spaceGridMaxY--; - // Centeral contact friction and bounce - // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why - // an avatar falls through in Z but not in X or Y when walking on a prim. - contact.surface.mode |= d.ContactFlags.SoftERP; - contact.surface.mu = nmAvatarObjectContactFriction; - contact.surface.bounce = nmAvatarObjectContactBounce; - contact.surface.soft_cfm = 0.010f; - contact.surface.soft_erp = 0.010f; + // create 4 off world spaces (x<0,x>max,y<0,y>max) + staticPrimspaceOffRegion = new IntPtr[4]; - // Terrain contact friction and Bounce - // This is the *non* moving version. Use this when an avatar - // isn't moving to keep it in place better - TerrainContact.surface.mode |= d.ContactFlags.SoftERP; - TerrainContact.surface.mu = nmTerrainContactFriction; - TerrainContact.surface.bounce = nmTerrainContactBounce; - TerrainContact.surface.soft_erp = nmTerrainContactERP; - - WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM); - WaterContact.surface.mu = 0f; // No friction - WaterContact.surface.bounce = 0.0f; // No bounce - WaterContact.surface.soft_cfm = 0.010f; - WaterContact.surface.soft_erp = 0.010f; - - // Prim contact friction and bounce - // THis is the *non* moving version of friction and bounce - // Use this when an avatar comes in contact with a prim - // and is moving - AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction; - AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce; - - // Terrain contact friction bounce and various error correcting calculations - // Use this when an avatar is in contact with the terrain and moving. - AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP; - AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction; - AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce; - AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP; - - /* - - Stone = 0, - /// - Metal = 1, - /// - Glass = 2, - /// - Wood = 3, - /// - Flesh = 4, - /// - Plastic = 5, - /// - Rubber = 6 - */ - - m_materialContacts = new d.Contact[7,2]; - - m_materialContacts[(int)Material.Stone, 0] = new d.Contact(); - m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Stone, 1] = new d.Contact(); - m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Metal, 0] = new d.Contact(); - m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Metal, 1] = new d.Contact(); - m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Glass, 0] = new d.Contact(); - m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f; - m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f; - m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f; - - /* - private float nmAvatarObjectContactFriction = 250f; - private float nmAvatarObjectContactBounce = 0.1f; - - private float mAvatarObjectContactFriction = 75f; - private float mAvatarObjectContactBounce = 0.1f; - */ - m_materialContacts[(int)Material.Glass, 1] = new d.Contact(); - m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f; - m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f; - m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Wood, 0] = new d.Contact(); - m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Wood, 1] = new d.Contact(); - m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Flesh, 0] = new d.Contact(); - m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Flesh, 1] = new d.Contact(); - m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Plastic, 0] = new d.Contact(); - m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Plastic, 1] = new d.Contact(); - m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Rubber, 0] = new d.Contact(); - m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Rubber, 1] = new d.Contact(); - m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f; - - d.HashSpaceSetLevels(space, HashspaceLow, HashspaceHigh); - - // Set the gravity,, don't disable things automatically (we set it explicitly on some things) - - d.WorldSetGravity(world, gravityx, gravityy, gravityz); - d.WorldSetContactSurfaceLayer(world, contactsurfacelayer); - - d.WorldSetLinearDamping(world, 256f); - d.WorldSetAngularDamping(world, 256f); - d.WorldSetAngularDampingThreshold(world, 256f); - d.WorldSetLinearDampingThreshold(world, 256f); - d.WorldSetMaxAngularSpeed(world, 256f); - - d.WorldSetQuickStepNumIterations(world, m_physicsiterations); - //d.WorldSetContactMaxCorrectingVel(world, 1000.0f); - - for (int i = 0; i < staticPrimspace.GetLength(0); i++) + for (i = 0; i < 4; i++) { - for (int j = 0; j < staticPrimspace.GetLength(1); j++) - { - staticPrimspace[i, j] = IntPtr.Zero; - } + newspace = d.HashSpaceCreate(StaticSpace); + d.GeomSetCategoryBits(newspace, (int)CollisionCategories.Space); + waitForSpaceUnlock(newspace); + d.SpaceSetSublevel(newspace, 2); + d.HashSpaceSetLevels(newspace, -2, 8); + d.GeomSetCategoryBits(newspace, (uint)(CollisionCategories.Space | + CollisionCategories.Geom | + CollisionCategories.Land | + CollisionCategories.Water | + CollisionCategories.Phantom | + CollisionCategories.VolumeDtc + )); + d.GeomSetCollideBits(newspace, 0); + + staticPrimspaceOffRegion[i] = newspace; } - _worldInitialized = true; + m_lastframe = DateTime.UtcNow; + m_lastMeshExpire = m_lastframe; + } + + internal void waitForSpaceUnlock(IntPtr space) + { + //if (space != IntPtr.Zero) + //while (d.SpaceLockQuery(space)) { } // Wait and do nothing } #region Collision Detection - /// - /// Collides two geometries. - /// - /// - /// - /// /param> - /// - /// - /// - private int CollideGeoms( - IntPtr geom1, IntPtr geom2, int maxContacts, d.ContactGeom[] contactsArray, int contactGeomSize) + // sets a global contact for a joint for contactgeom , and base contact description) + private IntPtr CreateContacJoint(ref d.ContactGeom contactGeom,bool smooth) { - int count; + if (m_global_contactcount >= maxContactsbeforedeath) + return IntPtr.Zero; - lock (OdeScene.UniversalColliderSyncObject) - { - // We do this inside the lock so that we don't count any delay in acquiring it - if (CollectStats) - m_nativeCollisionStartTick = Util.EnvironmentTickCount(); + m_global_contactcount++; + if(smooth) + SharedTmpcontact.geom.depth = contactGeom.depth * 0.05f; + else + SharedTmpcontact.geom.depth = contactGeom.depth; + SharedTmpcontact.geom.pos = contactGeom.pos; + SharedTmpcontact.geom.normal = contactGeom.normal; - count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize); - } - - // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably - // negligable - if (CollectStats) - m_stats[ODENativeGeomCollisionFrameMsStatName] - += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); - - return count; + IntPtr contact = new IntPtr(GlobalContactsArray.ToInt64() + (Int64)(m_global_contactcount * d.Contact.unmanagedSizeOf)); + Marshal.StructureToPtr(SharedTmpcontact, contact, true); + return d.JointCreateContactPtr(world, contactgroup, contact); } - /// - /// Collide two spaces or a space and a geometry. - /// - /// - /// /param> - /// - private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data) + private bool GetCurContactGeom(int index, ref d.ContactGeom newcontactgeom) { - if (CollectStats) - { - m_inCollisionTiming = true; - m_nativeCollisionStartTick = Util.EnvironmentTickCount(); - } + if (ContactgeomsArray == IntPtr.Zero || index >= contactsPerCollision) + return false; - d.SpaceCollide2(space1, space2, data, nearCallback); - - if (CollectStats && m_inCollisionTiming) - { - m_stats[ODENativeSpaceCollisionFrameMsStatName] - += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); - m_inCollisionTiming = false; - } + IntPtr contactptr = new IntPtr(ContactgeomsArray.ToInt64() + (Int64)(index * d.ContactGeom.unmanagedSizeOf)); + newcontactgeom = (d.ContactGeom)Marshal.PtrToStructure(contactptr, typeof(d.ContactGeom)); + return true; } /// @@ -929,70 +674,50 @@ namespace OpenSim.Region.PhysicsModule.ODE /// The space that contains the geoms. Remember, spaces are also geoms /// a geometry or space /// another geometry or space + /// + private void near(IntPtr space, IntPtr g1, IntPtr g2) { - if (CollectStats && m_inCollisionTiming) - { - m_stats[ODENativeSpaceCollisionFrameMsStatName] - += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); - m_inCollisionTiming = false; - } - -// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space); // no lock here! It's invoked from within Simulate(), which is thread-locked + if (m_global_contactcount >= maxContactsbeforedeath) + return; + // Test if we're colliding a geom with a space. // If so we have to drill down into the space recursively + if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) + return; + if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) { - if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) - return; - - // Separating static prim geometry spaces. // We'll be calling near recursivly if one // of them is a space to find all of the // contact points in the space try { - CollideSpaces(g1, g2, IntPtr.Zero); + d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); } catch (AccessViolationException) { - m_log.Error("[ODE SCENE]: Unable to collide test a space"); + m_log.Warn("[PHYSICS]: Unable to collide test a space"); return; } - //Colliding a space or a geom with a space or a geom. so drill down - - //Collide all geoms in each space.. - //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); - //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback); + //here one should check collisions of geoms inside a space + // but on each space we only should have geoms that not colide amoung each other + // so we don't dig inside spaces return; } - if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) - return; - + // get geom bodies to check if we already a joint contact + // guess this shouldn't happen now IntPtr b1 = d.GeomGetBody(g1); IntPtr b2 = d.GeomGetBody(g2); // d.GeomClassID id = d.GeomGetClass(g1); - String name1 = null; - String name2 = null; - - if (!geom_name_map.TryGetValue(g1, out name1)) - { - name1 = "null"; - } - if (!geom_name_map.TryGetValue(g2, out name2)) - { - name2 = "null"; - } - // Figure out how many contact points we have int count = 0; - try { // Colliding Geom To Geom @@ -1003,444 +728,329 @@ namespace OpenSim.Region.PhysicsModule.ODE if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) return; + /* + // debug + PhysicsActor dp2; + if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass) + { + d.AABB aabb; + d.GeomGetAABB(g2, out aabb); + float x = aabb.MaxX - aabb.MinX; + float y = aabb.MaxY - aabb.MinY; + float z = aabb.MaxZ - aabb.MinZ; + if (x > 60.0f || y > 60.0f || z > 60.0f) + { + if (!actor_name_map.TryGetValue(g2, out dp2)) + m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2"); + else + m_log.WarnFormat("[PHYSICS]: land versus large prim geo {0},size {1}, AABBsize <{2},{3},{4}>, at {5} ori {6},({7})", + dp2.Name, dp2.Size, x, y, z, + dp2.Position.ToString(), + dp2.Orientation.ToString(), + dp2.Orientation.Length()); + return; + } + } + // + */ - count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.unmanagedSizeOf); - // All code after this is only relevant if we have any collisions - if (count <= 0) - return; - - if (count > contacts.Length) - m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); + if (d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc || + d.GeomGetCategoryBits(g2) == (uint)CollisionCategories.VolumeDtc) + { + int cflags; + unchecked + { + cflags = (int)(1 | d.CONTACTS_UNIMPORTANT); + } + count = d.CollidePtr(g1, g2, cflags, ContactgeomsArray, d.ContactGeom.unmanagedSizeOf); + } + else + count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray, d.ContactGeom.unmanagedSizeOf); } catch (SEHException) { - m_log.Error( - "[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."); + 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.drelease(world); base.TriggerPhysicsBasedRestart(); } catch (Exception e) { - m_log.ErrorFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message); + m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message); return; } + // contacts done + if (count == 0) + return; + + // try get physical actors PhysicsActor p1; PhysicsActor p2; - - p1ExpectedPoints = 0; - p2ExpectedPoints = 0; - + if (!actor_name_map.TryGetValue(g1, out p1)) { - p1 = PANull; + m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 1"); + return; } if (!actor_name_map.TryGetValue(g2, out p2)) { - p2 = PANull; + m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2"); + return; } + + // get first contact + d.ContactGeom curContact = new d.ContactGeom(); + + if (!GetCurContactGeom(0, ref curContact)) + return; + ContactPoint maxDepthContact = new ContactPoint(); - if (p1.CollisionScore + count >= float.MaxValue) - p1.CollisionScore = 0; - p1.CollisionScore += count; - if (p2.CollisionScore + count >= float.MaxValue) - p2.CollisionScore = 0; - p2.CollisionScore += count; - - for (int i = 0; i < count; i++) + // do volume detection case + if ((p1.IsVolumeDtc || p2.IsVolumeDtc)) { - d.ContactGeom curContact = contacts[i]; - - if (curContact.depth > maxDepthContact.PenetrationDepth) - { - maxDepthContact = new ContactPoint( - new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), - new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), - curContact.depth + maxDepthContact = new ContactPoint( + new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), + new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), + curContact.depth, false ); - } - - //m_log.Warn("[CCOUNT]: " + count); - IntPtr joint; - // If we're colliding with terrain, use 'TerrainContact' instead of contact. - // allows us to have different settings - - // We only need to test p2 for 'jump crouch purposes' - if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim) - { - // Testing if the collision is at the feet of the avatar - - //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f)); - if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f)) - p2.IsColliding = true; - } - else - { - p2.IsColliding = true; - } - - //if ((framecount % m_returncollisions) == 0) - - switch (p1.PhysicsActorType) - { - case (int)ActorTypes.Agent: - p1ExpectedPoints = avatarExpectedContacts; - p2.CollidingObj = true; - break; - case (int)ActorTypes.Prim: - if (p1 != null && p1 is OdePrim) - p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts; - - if (p2.Velocity.LengthSquared() > 0.0f) - p2.CollidingObj = true; - break; - case (int)ActorTypes.Unknown: - p2.CollidingGround = true; - break; - default: - p2.CollidingGround = true; - break; - } - - // we don't want prim or avatar to explode - - #region InterPenetration Handling - Unintended physics explosions - - if (curContact.depth >= 0.08f) - { - if (curContact.depth >= 1.00f) - { - //m_log.Info("[P]: " + contact.depth.ToString()); - if ((p2.PhysicsActorType == (int) ActorTypes.Agent && - p1.PhysicsActorType == (int) ActorTypes.Unknown) || - (p1.PhysicsActorType == (int) ActorTypes.Agent && - p2.PhysicsActorType == (int) ActorTypes.Unknown)) - { - if (p2.PhysicsActorType == (int) ActorTypes.Agent) - { - if (p2 is OdeCharacter) - { - OdeCharacter character = (OdeCharacter) p2; - - //p2.CollidingObj = true; - curContact.depth = 0.00000003f; - p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f); - curContact.pos = - new d.Vector3(curContact.pos.X + (p1.Size.X/2), - curContact.pos.Y + (p1.Size.Y/2), - curContact.pos.Z + (p1.Size.Z/2)); - character.SetPidStatus(true); - } - } - - if (p1.PhysicsActorType == (int) ActorTypes.Agent) - { - if (p1 is OdeCharacter) - { - OdeCharacter character = (OdeCharacter) p1; - - //p2.CollidingObj = true; - curContact.depth = 0.00000003f; - p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f); - curContact.pos = - new d.Vector3(curContact.pos.X + (p1.Size.X/2), - curContact.pos.Y + (p1.Size.Y/2), - curContact.pos.Z + (p1.Size.Z/2)); - character.SetPidStatus(true); - } - } - } - } - } - - #endregion - - // Logic for collision handling - // Note, that if *all* contacts are skipped (VolumeDetect) - // The prim still detects (and forwards) collision events but - // appears to be phantom for the world - Boolean skipThisContact = false; - - if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) - skipThisContact = true; // No collision on volume detect prims - - if (av_av_collisions_off) - if ((p1 is OdeCharacter) && (p2 is OdeCharacter)) - skipThisContact = true; - - if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) - skipThisContact = true; // No collision on volume detect prims - - if (!skipThisContact && curContact.depth < 0f) - skipThisContact = true; - - if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType)) - skipThisContact = true; - - const int maxContactsbeforedeath = 4000; - joint = IntPtr.Zero; - - if (!skipThisContact) - { - _perloopContact.Add(curContact); - - if (name1 == "Terrain" || name2 == "Terrain") - { - if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && - (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) - { - p2ExpectedPoints = avatarExpectedContacts; - // Avatar is moving on terrain, use the movement terrain contact - AvatarMovementTerrainContact.geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); - m_global_contactcount++; - } - } - else - { - if (p2.PhysicsActorType == (int)ActorTypes.Agent) - { - p2ExpectedPoints = avatarExpectedContacts; - // Avatar is standing on terrain, use the non moving terrain contact - TerrainContact.geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); - m_global_contactcount++; - } - } - else - { - if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim) - { - // prim prim contact - // int pj294950 = 0; - int movintYN = 0; - int material = (int) Material.Wood; - // prim terrain contact - if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) - { - movintYN = 1; - } - - if (p2 is OdePrim) - { - material = ((OdePrim) p2).m_material; - p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; - } - - // Unnessesary because p1 is defined above - //if (p1 is OdePrim) - // { - // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts; - // } - //m_log.DebugFormat("Material: {0}", material); - - m_materialContacts[material, movintYN].geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); - m_global_contactcount++; - } - } - else - { - int movintYN = 0; - // prim terrain contact - if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) - { - movintYN = 1; - } - - int material = (int)Material.Wood; - - if (p2 is OdePrim) - { - material = ((OdePrim)p2).m_material; - p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; - } - - //m_log.DebugFormat("Material: {0}", material); - m_materialContacts[material, movintYN].geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); - m_global_contactcount++; - } - } - } - } - //if (p2.PhysicsActorType == (int)ActorTypes.Prim) - //{ - //m_log.Debug("[PHYSICS]: prim contacting with ground"); - //} - } - else if (name1 == "Water" || name2 == "Water") - { - /* - if ((p2.PhysicsActorType == (int) ActorTypes.Prim)) - { - } - else - { - } - */ - //WaterContact.surface.soft_cfm = 0.0000f; - //WaterContact.surface.soft_erp = 0.00000f; - if (curContact.depth > 0.1f) - { - curContact.depth *= 52; - //contact.normal = new d.Vector3(0, 0, 1); - //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f); - } - - WaterContact.geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref WaterContact); - m_global_contactcount++; - } - //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth); - } - else - { - if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) - { - p2ExpectedPoints = avatarExpectedContacts; - if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) - { - // Avatar is moving on a prim, use the Movement prim contact - AvatarMovementprimContact.geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); - m_global_contactcount++; - } - } - else - { - // Avatar is standing still on a prim, use the non movement contact - contact.geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref contact); - m_global_contactcount++; - } - } - } - else if (p2.PhysicsActorType == (int)ActorTypes.Prim) - { - //p1.PhysicsActorType - int material = (int)Material.Wood; - - if (p2 is OdePrim) - { - material = ((OdePrim)p2).m_material; - p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; - } - - //m_log.DebugFormat("Material: {0}", material); - m_materialContacts[material, 0].geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]); - m_global_contactcount++; - } - } - } - - if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide! - { - d.JointAttach(joint, b1, b2); - m_global_contactcount++; - } - } collision_accounting_events(p1, p2, maxDepthContact); - - if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle)) - { - // If there are more then 3 contact points, it's likely - // that we've got a pile of objects, so ... - // We don't want to send out hundreds of terse updates over and over again - // so lets throttle them and send them again after it's somewhat sorted out. - p2.ThrottleUpdates = true; - } - //m_log.Debug(count.ToString()); - //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2); + return; } - } - private bool checkDupe(d.ContactGeom contactGeom, int atype) - { - if (!m_filterCollisions) - return false; + // big messy collision analises - bool result = false; + float mu = 0; + float bounce = 0; +// bool IgnoreNegSides = false; - ActorTypes at = (ActorTypes)atype; + ContactData contactdata1 = new ContactData(0, 0, false); + ContactData contactdata2 = new ContactData(0, 0, false); - foreach (d.ContactGeom contact in _perloopContact) + bool dop1ava = false; + bool dop2ava = false; + bool ignore = false; + bool smoothMesh = false; + + switch (p1.PhysicsActorType) { - //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))) + case (int)ActorTypes.Agent: { - if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) + dop1ava = true; + switch (p2.PhysicsActorType) { - result = true; - break; - } - } - } - else if (at == ActorTypes.Prim) - { - 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))) - { - 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; + case (int)ActorTypes.Agent: + case (int)ActorTypes.Prim: + break; + + default: + ignore = true; // avatar to terrain and water ignored break; - } } - //m_log.DebugFormat("[Collision]: 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)); + break; } - } + + case (int)ActorTypes.Prim: + { + switch (p2.PhysicsActorType) + { + case (int)ActorTypes.Agent: + dop2ava = true; + break; + + case (int)ActorTypes.Prim: + Vector3 relV = p1.rootVelocity - p2.rootVelocity; + float relVlenSQ = relV.LengthSquared(); + if (relVlenSQ > 0.0001f) + { + p1.CollidingObj = true; + p2.CollidingObj = true; + } + p1.getContactData(ref contactdata1); + p2.getContactData(ref contactdata2); + bounce = contactdata1.bounce * contactdata2.bounce; + mu = (float)Math.Sqrt(contactdata1.mu * contactdata2.mu); + + if (relVlenSQ > 0.01f) + mu *= frictionMovementMult; + + if(d.GeomGetClass(g2) == d.GeomClassID.TriMeshClass && + d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass) + smoothMesh = true; + break; + + case (int)ActorTypes.Ground: + p1.getContactData(ref contactdata1); + bounce = contactdata1.bounce * TerrainBounce; + mu = (float)Math.Sqrt(contactdata1.mu * TerrainFriction); + + Vector3 v1 = p1.rootVelocity; + if (Math.Abs(v1.X) > 0.1f || Math.Abs(v1.Y) > 0.1f) + mu *= frictionMovementMult; + p1.CollidingGround = true; + + if(d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass) + smoothMesh = true; + break; + + case (int)ActorTypes.Water: + default: + ignore = true; + break; + } + } + break; + + case (int)ActorTypes.Ground: + if (p2.PhysicsActorType == (int)ActorTypes.Prim) + { + p2.CollidingGround = true; + p2.getContactData(ref contactdata2); + bounce = contactdata2.bounce * TerrainBounce; + mu = (float)Math.Sqrt(contactdata2.mu * TerrainFriction); + +// if (curContact.side1 > 0) // should be 2 ? +// IgnoreNegSides = true; + Vector3 v2 = p2.rootVelocity; + if (Math.Abs(v2.X) > 0.1f || Math.Abs(v2.Y) > 0.1f) + mu *= frictionMovementMult; + + if(d.GeomGetClass(g2) == d.GeomClassID.TriMeshClass) + smoothMesh = true; + } + else + ignore = true; + break; + + case (int)ActorTypes.Water: + default: + break; } - return result; + if (ignore) + return; + + IntPtr Joint; + bool FeetCollision = false; + int ncontacts = 0; + + int i = 0; + + maxDepthContact = new ContactPoint(); + maxDepthContact.PenetrationDepth = float.MinValue; + ContactPoint minDepthContact = new ContactPoint(); + minDepthContact.PenetrationDepth = float.MaxValue; + + SharedTmpcontact.geom.depth = 0; + SharedTmpcontact.surface.mu = mu; + SharedTmpcontact.surface.bounce = bounce; + + d.ContactGeom altContact = new d.ContactGeom(); + bool useAltcontact = false; + bool noskip = true; + + if(dop1ava || dop2ava) + smoothMesh = false; + + while (true) + { + noskip = true; + useAltcontact = false; + + if (dop1ava) + { + if ((((OdeCharacter)p1).Collide(g1, g2, false, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision))) + { + if (p2.PhysicsActorType == (int)ActorTypes.Agent) + { + p1.CollidingObj = true; + p2.CollidingObj = true; + } + else if (p2.rootVelocity.LengthSquared() > 0.0f) + p2.CollidingObj = true; + } + else + noskip = false; + } + else if (dop2ava) + { + if ((((OdeCharacter)p2).Collide(g2, g1, true, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision))) + { + if (p1.PhysicsActorType == (int)ActorTypes.Agent) + { + p1.CollidingObj = true; + p2.CollidingObj = true; + } + else if (p1.rootVelocity.LengthSquared() > 0.0f) + p1.CollidingObj = true; + } + else + noskip = false; + } + + if (noskip) + { + if(useAltcontact) + Joint = CreateContacJoint(ref altContact,smoothMesh); + else + Joint = CreateContacJoint(ref curContact,smoothMesh); + + if (Joint == IntPtr.Zero) + break; + + d.JointAttach(Joint, b1, b2); + + ncontacts++; + + if (curContact.depth > maxDepthContact.PenetrationDepth) + { + maxDepthContact.Position.X = curContact.pos.X; + maxDepthContact.Position.Y = curContact.pos.Y; + maxDepthContact.Position.Z = curContact.pos.Z; + maxDepthContact.PenetrationDepth = curContact.depth; + maxDepthContact.CharacterFeet = FeetCollision; + } + + if (curContact.depth < minDepthContact.PenetrationDepth) + { + minDepthContact.PenetrationDepth = curContact.depth; + minDepthContact.SurfaceNormal.X = curContact.normal.X; + minDepthContact.SurfaceNormal.Y = curContact.normal.Y; + minDepthContact.SurfaceNormal.Z = curContact.normal.Z; + } + } + + if (++i >= count) + break; + + if (!GetCurContactGeom(i, ref curContact)) + break; + } + + if (ncontacts > 0) + { + maxDepthContact.SurfaceNormal.X = minDepthContact.SurfaceNormal.X; + maxDepthContact.SurfaceNormal.Y = minDepthContact.SurfaceNormal.Y; + maxDepthContact.SurfaceNormal.Z = minDepthContact.SurfaceNormal.Z; + + collision_accounting_events(p1, p2, maxDepthContact); + } } private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) { - // obj1LocalID = 0; - //returncollisions = false; - obj2LocalID = 0; - //ctype = 0; - //cStartStop = 0; -// if (!p2.SubscribedEvents() && !p1.SubscribedEvents()) -// return; + uint obj2LocalID = 0; + + // update actors collision score + if (p1.CollisionScore < float.MaxValue) + p1.CollisionScore += 1.0f; + if (p2.CollisionScore < float.MaxValue) + p2.CollisionScore += 1.0f; + bool p1events = p1.SubscribedEvents(); bool p2events = p2.SubscribedEvents(); @@ -1454,369 +1064,170 @@ namespace OpenSim.Region.PhysicsModule.ODE Vector3 vel = Vector3.Zero; if (p2 != null && p2.IsPhysical) - vel = p2.Velocity; + vel = p2.rootVelocity; if (p1 != null && p1.IsPhysical) - vel -= p1.Velocity; + vel -= p1.rootVelocity; contact.RelativeSpeed = Vector3.Dot(vel, contact.SurfaceNormal); - switch ((ActorTypes)p2.PhysicsActorType) + switch ((ActorTypes)p1.PhysicsActorType) { case ActorTypes.Agent: - cc2 = (OdeCharacter)p2; - - // obj1LocalID = cc2.m_localID; - switch ((ActorTypes)p1.PhysicsActorType) + case ActorTypes.Prim: + { + switch ((ActorTypes)p2.PhysicsActorType) { case ActorTypes.Agent: - cc1 = (OdeCharacter)p1; - obj2LocalID = cc1.LocalID; - cc1.AddCollisionEvent(cc2.LocalID, contact); - break; - case ActorTypes.Prim: - if (p1 is OdePrim) + if (p2events) { - cp1 = (OdePrim) p1; - obj2LocalID = cp1.LocalID; - cp1.AddCollisionEvent(cc2.LocalID, contact); + AddCollisionEventReporting(p2); + p2.AddCollisionEvent(p1.ParentActor.LocalID, contact); } + obj2LocalID = p2.ParentActor.LocalID; break; case ActorTypes.Ground: case ActorTypes.Unknown: + default: obj2LocalID = 0; break; } - - cc2.AddCollisionEvent(obj2LocalID, contact); - break; - - case ActorTypes.Prim: - - if (p2 is OdePrim) + if (p1events) { - cp2 = (OdePrim) p2; - - // obj1LocalID = cp2.m_localID; - switch ((ActorTypes) p1.PhysicsActorType) - { - case ActorTypes.Agent: - if (p1 is OdeCharacter) - { - cc1 = (OdeCharacter) p1; - obj2LocalID = cc1.LocalID; - cc1.AddCollisionEvent(cp2.LocalID, contact); - } - break; - case ActorTypes.Prim: - - if (p1 is OdePrim) - { - cp1 = (OdePrim) p1; - obj2LocalID = cp1.LocalID; - cp1.AddCollisionEvent(cp2.LocalID, contact); - } - break; - - case ActorTypes.Ground: - case ActorTypes.Unknown: - obj2LocalID = 0; - break; - } - - cp2.AddCollisionEvent(obj2LocalID, contact); + contact.SurfaceNormal = -contact.SurfaceNormal; + contact.RelativeSpeed = -contact.RelativeSpeed; + AddCollisionEventReporting(p1); + p1.AddCollisionEvent(obj2LocalID, contact); } break; + } + case ActorTypes.Ground: + case ActorTypes.Unknown: + default: + { + if (p2events && !p2.IsVolumeDtc) + { + AddCollisionEventReporting(p2); + p2.AddCollisionEvent(0, contact); + } + break; + } } } + /// /// This is our collision testing routine in ODE /// + /// private void collision_optimized() { - _perloopContact.Clear(); - - foreach (OdeCharacter chr in _characters) - { - // Reset the collision values to false - // since we don't know if we're colliding yet - 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. + lock (_characters) + { try { - CollideSpaces(space, chr.Shell, IntPtr.Zero); + foreach (OdeCharacter chr in _characters) + { + if (chr == null) + continue; + + chr.IsColliding = false; + // chr.CollidingGround = false; not done here + chr.CollidingObj = false; + + if(chr.Body == IntPtr.Zero || chr.collider == IntPtr.Zero ) + continue; + + // do colisions with static space + d.SpaceCollide2(chr.collider, StaticSpace, IntPtr.Zero, nearCallback); + + // no coll with gnd + } + // chars with chars + d.SpaceCollide(CharsSpace, IntPtr.Zero, nearCallback); + } catch (AccessViolationException) { - m_log.ErrorFormat("[ODE SCENE]: Unable to space collide {0}", PhysicsSceneName); + m_log.Warn("[PHYSICS]: Unable to collide Character to static space"); } - - //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; - //} + } - if (CollectStats) + lock (_activeprims) { - m_tempAvatarCollisionsThisFrame = _perloopContact.Count; - m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame; - } - - List removeprims = null; - foreach (OdePrim chr in _activeprims) - { - if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled)) + foreach (OdePrim aprim in _activeprims) { - try + aprim.CollisionScore = 0; + aprim.IsColliding = false; + } + } + lock (_activegroups) + { + try + { + foreach (OdePrim aprim in _activegroups) { - lock (chr) + if(!aprim.m_outbounds && d.BodyIsEnabled(aprim.Body) && + aprim.collide_geom != IntPtr.Zero) { - if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false) - { - CollideSpaces(space, chr.prim_geom, IntPtr.Zero); - } - else - { - if (removeprims == null) - { - removeprims = new List(); - } - removeprims.Add(chr); - m_log.Error( - "[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!"); - } + d.SpaceCollide2(StaticSpace, aprim.collide_geom, IntPtr.Zero, nearCallback); + d.SpaceCollide2(GroundSpace, aprim.collide_geom, IntPtr.Zero, nearCallback); } } - catch (AccessViolationException) - { - m_log.Error("[ODE SCENE]: Unable to space collide"); - } + } + catch (Exception e) + { + m_log.Warn("[PHYSICS]: Unable to collide Active to Static: " + e.Message); } } - if (CollectStats) - m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame; - - if (removeprims != null) + // colide active amoung them + try { - foreach (OdePrim chr in removeprims) - { - _activeprims.Remove(chr); - } + d.SpaceCollide(ActiveSpace, IntPtr.Zero, nearCallback); + } + catch (Exception e) + { + m_log.Warn("[PHYSICS]: Unable to collide in Active: " + e.Message); + } + + // and with chars + try + { + d.SpaceCollide2(CharsSpace,ActiveSpace, IntPtr.Zero, nearCallback); + } + catch (Exception e) + { + m_log.Warn("[PHYSICS]: Unable to collide Active to Character: " + e.Message); } } #endregion - - // Recovered for use by fly height. Kitto Flora - internal float GetTerrainHeightAtXY(float x, float y) - { - IntPtr heightFieldGeom = IntPtr.Zero; - int offsetX = 0; - int offsetY = 0; - - if(RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom)) - { - if (heightFieldGeom != IntPtr.Zero) - { - if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom)) - { - - int index; - - - if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y || - (int)x < 0.001f || (int)y < 0.001f) - return 0; - - x = x - offsetX + 1f; - y = y - offsetY + 1f; - - // map is rotated - index = (int)x * ((int)m_regionHeight + 3) + (int)y; - - if (index < TerrainHeightFieldHeights[heightFieldGeom].Length) - { - //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]); - return (float)TerrainHeightFieldHeights[heightFieldGeom][index]; - } - - else - return 0f; - } - else - { - return 0f; - } - - } - else - { - return 0f; - } - - } - else - { - return 0f; - } - } -// End recovered. Kitto Flora - /// /// Add actor to the list that should receive collision events in the simulate loop. /// /// - internal void AddCollisionEventReporting(PhysicsActor obj) + public void AddCollisionEventReporting(PhysicsActor obj) { -// m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID); - - lock (m_collisionEventActorsChanges) - m_collisionEventActorsChanges[obj.LocalID] = obj; + if (!_collisionEventPrim.Contains(obj)) + _collisionEventPrim.Add(obj); } /// /// Remove actor from the list that should receive collision events in the simulate loop. /// /// - internal void RemoveCollisionEventReporting(PhysicsActor obj) + public void RemoveCollisionEventReporting(PhysicsActor obj) { -// m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID); - - lock (m_collisionEventActorsChanges) - m_collisionEventActorsChanges[obj.LocalID] = null; - } - - #region Add/Remove Entities - - public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) - { - d.AllocateODEDataForThread(0); - - OdeCharacter newAv - = new OdeCharacter( - avName, this, position, velocity, size, avPIDD, avPIDP, - avCapRadius, avStandupTensor, avDensity, - avMovementDivisorWalk, avMovementDivisorRun); - - newAv.Flying = isFlying; - newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; - newAv.m_avatarplanted = avplanted; - - return newAv; - } - - public override void RemoveAvatar(PhysicsActor actor) - { -// m_log.DebugFormat( -// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}", -// actor.Name, actor.LocalID, Name); - - lock (OdeLock) + lock(_collisionEventPrimRemove) { - d.AllocateODEDataForThread(0); - - ((OdeCharacter) actor).Destroy(); + if (_collisionEventPrim.Contains(obj) && !_collisionEventPrimRemove.Contains(obj)) + _collisionEventPrimRemove.Add(obj); } } - internal void AddCharacter(OdeCharacter chr) - { - chr.m_avatarplanted = avplanted; - if (!_characters.Contains(chr)) - { - _characters.Add(chr); - -// m_log.DebugFormat( -// "[ODE SCENE]: Adding physics character {0} {1} to physics scene {2}. Count now {3}", -// chr.Name, chr.LocalID, Name, _characters.Count); - - if (chr.bad) - 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) - { - if (_characters.Contains(chr)) - { - _characters.Remove(chr); - -// m_log.DebugFormat( -// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}. Count now {3}", -// chr.Name, chr.LocalID, Name, _characters.Count); - } - 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, - PrimitiveBaseShape pbs, bool isphysical, uint localID) - { - Vector3 pos = position; - Vector3 siz = size; - Quaternion rot = rotation; - - - OdePrim newPrim; - lock (OdeLock) - { - d.AllocateODEDataForThread(0); - newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical); - - lock (_prims) - _prims.Add(newPrim); - } - newPrim.LocalID = localID; - return newPrim; - } - - /// - /// Make this prim subject to physics. - /// - /// - internal void ActivatePrim(OdePrim prim) - { - // adds active prim.. (ones that should be iterated over in collisions_optimized - 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, - Vector3 size, Quaternion rotation, bool isPhysical, uint localid) - { -// m_log.DebugFormat("[ODE SCENE]: Adding physics prim {0} {1} to physics scene {2}", primName, localid, Name); - - return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid); - } - public override float TimeDilation { get { return m_timeDilation; } @@ -1824,362 +1235,133 @@ namespace OpenSim.Region.PhysicsModule.ODE public override bool SupportsNINJAJoints { - get { return m_NINJA_physics_joints_enabled; } + get { return false; } } - // internal utility function: must be called within a lock (OdeLock) - private void InternalAddActiveJoint(PhysicsJoint joint) + #region Add/Remove Entities + + public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) { - activeJoints.Add(joint); - SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint); + return null; } - // internal utility function: must be called within a lock (OdeLock) - private void InternalAddPendingJoint(OdePhysicsJoint joint) + public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, float feetOffset, bool isFlying) { - pendingJoints.Add(joint); - SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint); + OdeCharacter newAv = new OdeCharacter(localID, avName, this, position, + size, feetOffset, avDensity, avMovementDivisorWalk, avMovementDivisorRun); + newAv.Flying = isFlying; + newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; + + return newAv; } - // internal utility function: must be called within a lock (OdeLock) - private void InternalRemovePendingJoint(PhysicsJoint joint) + public void AddCharacter(OdeCharacter chr) { - pendingJoints.Remove(joint); - SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene); - } - - // internal utility function: must be called within a lock (OdeLock) - private void InternalRemoveActiveJoint(PhysicsJoint joint) - { - activeJoints.Remove(joint); - SOPName_to_activeJoint.Remove(joint.ObjectNameInScene); - } - - public override void DumpJointInfo() - { - string hdr = "[NINJA] JOINTINFO: "; - foreach (PhysicsJoint j in pendingJoints) + lock (_characters) { - m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); - } - m_log.Debug(hdr + pendingJoints.Count + " total pending joints"); - foreach (string jointName in SOPName_to_pendingJoint.Keys) - { - m_log.Debug(hdr + " pending joints dict contains Name: " + jointName); - } - m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries"); - foreach (PhysicsJoint j in activeJoints) - { - m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); - } - m_log.Debug(hdr + activeJoints.Count + " total active joints"); - foreach (string jointName in SOPName_to_activeJoint.Keys) - { - m_log.Debug(hdr + " active joints dict contains Name: " + jointName); - } - m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries"); - - m_log.Debug(hdr + " Per-body joint connectivity information follows."); - m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints."); - foreach (string actorName in joints_connecting_actor.Keys) - { - m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it"); - foreach (PhysicsJoint j in joints_connecting_actor[actorName]) + if (!_characters.Contains(chr)) { - m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); - } - m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor"); - } - } - - public override void RequestJointDeletion(string ObjectNameInScene) - { - lock (externalJointRequestsLock) - { - if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously - { - requestedJointsToBeDeleted.Add(ObjectNameInScene); + _characters.Add(chr); + if (chr.bad) + m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid); } } } - private void DeleteRequestedJoints() + public void RemoveCharacter(OdeCharacter chr) { - List myRequestedJointsToBeDeleted; - lock (externalJointRequestsLock) + lock (_characters) { - // make a local copy of the shared list for processing (threading issues) - myRequestedJointsToBeDeleted = new List(requestedJointsToBeDeleted); - } - - foreach (string jointName in myRequestedJointsToBeDeleted) - { - lock (OdeLock) + if (_characters.Contains(chr)) { - //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName); - if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName)) - { - OdePhysicsJoint joint = null; - if (SOPName_to_activeJoint.ContainsKey(jointName)) - { - joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint; - InternalRemoveActiveJoint(joint); - } - else if (SOPName_to_pendingJoint.ContainsKey(jointName)) - { - joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint; - InternalRemovePendingJoint(joint); - } - - if (joint != null) - { - //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames); - for (int iBodyName = 0; iBodyName < 2; iBodyName++) - { - string bodyName = joint.BodyNames[iBodyName]; - if (bodyName != "NULL") - { - joints_connecting_actor[bodyName].Remove(joint); - if (joints_connecting_actor[bodyName].Count == 0) - { - joints_connecting_actor.Remove(bodyName); - } - } - } - - DoJointDeactivated(joint); - if (joint.jointID != IntPtr.Zero) - { - d.JointDestroy(joint.jointID); - joint.jointID = IntPtr.Zero; - //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName); - } - else - { - //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName); - } - } - else - { - // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName); - } - } - else - { - // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName); - } - } - } - - // remove processed joints from the shared list - lock (externalJointRequestsLock) - { - foreach (string jointName in myRequestedJointsToBeDeleted) - { - requestedJointsToBeDeleted.Remove(jointName); + _characters.Remove(chr); } } } - // for pending joints we don't know if their associated bodies exist yet or not. - // the joint is actually created during processing of the taints - private void CreateRequestedJoints() + public void BadCharacter(OdeCharacter chr) { - List myRequestedJointsToBeCreated; - lock (externalJointRequestsLock) + lock (_badCharacter) { - // make a local copy of the shared list for processing (threading issues) - myRequestedJointsToBeCreated = new List(requestedJointsToBeCreated); - } - - foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) - { - lock (OdeLock) - { - if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null) - { - DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); - continue; - } - if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null) - { - DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); - continue; - } - - InternalAddPendingJoint(joint as OdePhysicsJoint); - - if (joint.BodyNames.Count >= 2) - { - for (int iBodyName = 0; iBodyName < 2; iBodyName++) - { - string bodyName = joint.BodyNames[iBodyName]; - if (bodyName != "NULL") - { - if (!joints_connecting_actor.ContainsKey(bodyName)) - { - joints_connecting_actor.Add(bodyName, new List()); - } - joints_connecting_actor[bodyName].Add(joint); - } - } - } - } - } - - // remove processed joints from shared list - lock (externalJointRequestsLock) - { - foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) - { - requestedJointsToBeCreated.Remove(joint); - } + if (!_badCharacter.Contains(chr)) + _badCharacter.Add(chr); } } - /// - /// Add a request for joint creation. - /// - /// - /// this joint will just be added to a waiting list that is NOT processed during the main - /// Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public override PhysicsJoint RequestJointCreation( - string objectNameInScene, PhysicsJointType jointType, Vector3 position, - Quaternion rotation, string parms, List bodyNames, string trackedBodyName, Quaternion localRotation) + public override void RemoveAvatar(PhysicsActor actor) { - OdePhysicsJoint joint = new OdePhysicsJoint(); - joint.ObjectNameInScene = objectNameInScene; - joint.Type = jointType; - joint.Position = position; - joint.Rotation = rotation; - joint.RawParams = parms; - joint.BodyNames = new List(bodyNames); - joint.TrackedBodyName = trackedBodyName; - joint.LocalRotation = localRotation; - joint.jointID = IntPtr.Zero; - joint.ErrorMessageCount = 0; - - lock (externalJointRequestsLock) - { - if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice - { - requestedJointsToBeCreated.Add(joint); - } - } - - return joint; - } - - private void RemoveAllJointsConnectedToActor(PhysicsActor actor) - { - //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]) - { - jointsToRemove.Add(j); - } - foreach (PhysicsJoint j in jointsToRemove) - { - //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene); - RequestJointDeletion(j.ObjectNameInScene); - //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene); - j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing) - } - } - } - - public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor) - { - //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start"); + //m_log.Debug("[PHYSICS]:ODELOCK"); lock (OdeLock) { - //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock"); - RemoveAllJointsConnectedToActor(actor); + d.AllocateODEDataForThread(0); + ((OdeCharacter) actor).Destroy(); } } - // normally called from within OnJointMoved, which is called from within a lock (OdeLock) - public override Vector3 GetJointAnchor(PhysicsJoint joint) - { - Debug.Assert(joint.IsInPhysicsEngine); - d.Vector3 pos = new d.Vector3(); - if (!(joint is OdePhysicsJoint)) + public void addActivePrim(OdePrim activatePrim) + { + // adds active prim.. + lock (_activeprims) { - DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); + if (!_activeprims.Contains(activatePrim)) + _activeprims.Add(activatePrim); } - else - { - OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; - switch (odeJoint.Type) - { - case PhysicsJointType.Ball: - d.JointGetBallAnchor(odeJoint.jointID, out pos); - break; - case PhysicsJointType.Hinge: - d.JointGetHingeAnchor(odeJoint.jointID, out pos); - break; - } - } - return new Vector3(pos.X, pos.Y, pos.Z); } - /// - /// Get joint axis. - /// - /// - /// normally called from within OnJointMoved, which is called from within a lock (OdeLock) - /// WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function - /// appears to be unreliable. Fortunately we can compute the joint axis ourselves by - /// keeping track of the joint's original orientation relative to one of the involved bodies. - /// - /// - /// - public override Vector3 GetJointAxis(PhysicsJoint joint) + public void addActiveGroups(OdePrim activatePrim) { - Debug.Assert(joint.IsInPhysicsEngine); - d.Vector3 axis = new d.Vector3(); - - if (!(joint is OdePhysicsJoint)) + lock (_activegroups) { - DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); + if (!_activegroups.Contains(activatePrim)) + _activegroups.Add(activatePrim); } - else - { - OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; - switch (odeJoint.Type) - { - case PhysicsJointType.Ball: - DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene); - break; - case PhysicsJointType.Hinge: - d.JointGetHingeAxis(odeJoint.jointID, out axis); - break; - } - } - return new Vector3(axis.X, axis.Y, axis.Z); } - /// - /// Stop this prim being subject to physics - /// - /// - internal void DeactivatePrim(OdePrim prim) + private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, + PrimitiveBaseShape pbs, bool isphysical, bool isPhantom, byte shapeType, uint localID) { - _activeprims.Remove(prim); + OdePrim newPrim; + lock (OdeLock) + { + + newPrim = new OdePrim(name, this, position, size, rotation, pbs, isphysical, isPhantom, shapeType, localID); + } + return newPrim; + } + + public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, + Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, uint localid) + { + return AddPrim(primName, position, size, rotation, pbs, isPhysical, isPhantom, 0 , localid); + } + + + public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, + Vector3 size, Quaternion rotation, bool isPhysical, uint localid) + { + return AddPrim(primName, position, size, rotation, pbs, isPhysical,false, 0, localid); + } + + public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, + Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapeType, uint localid) + { + return AddPrim(primName, position, size, rotation, pbs, isPhysical,isPhantom, shapeType, localid); + } + + public void remActivePrim(OdePrim deactivatePrim) + { + lock (_activeprims) + { + _activeprims.Remove(deactivatePrim); + } + } + public void remActiveGroup(OdePrim deactivatePrim) + { + lock (_activegroups) + { + _activegroups.Remove(deactivatePrim); + } } public override void RemovePrim(PhysicsActor prim) @@ -2188,65 +1370,73 @@ namespace OpenSim.Region.PhysicsModule.ODE // removed in the next physics simulate pass. if (prim is OdePrim) { - lock (OdeLock) +// lock (OdeLock) { - OdePrim p = (OdePrim) prim; - + + OdePrim p = (OdePrim)prim; p.setPrimForRemoval(); - AddPhysicsActorTaint(prim); } } } - /// - /// This is called from within simulate but outside the locked portion - /// We need to do our own locking here - /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in - /// Simulate() -- justincc). - /// - /// Essentially, we need to remove the prim from our space segment, whatever segment it's in. - /// - /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory - /// that the space was using. - /// - /// - internal void RemovePrimThreadLocked(OdePrim prim) + public void RemovePrimThreadLocked(OdePrim prim) { -// m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID); - + //Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName); lock (prim) { - RemoveCollisionEventReporting(prim); - - if (prim.prim_geom != IntPtr.Zero) - { - prim.ResetTaints(); - - if (prim.IsPhysical) - { - prim.disableBody(); - if (prim.childPrim) - { - prim.childPrim = false; - prim.Body = IntPtr.Zero; - prim.m_disabled = true; - prim.IsPhysical = false; - } - - - } - prim.m_targetSpace = IntPtr.Zero; - if (!prim.RemoveGeom()) - m_log.Warn("[ODE SCENE]: Unable to remove prim from physics scene"); - - lock (_prims) - _prims.Remove(prim); - - - if (SupportsNINJAJoints) - RemoveAllJointsConnectedToActorThreadLocked(prim); - } +// RemoveCollisionEventReporting(prim); + lock (_prims) + _prims.Remove(prim.LocalID); } + + } + + public void addToPrims(OdePrim prim) + { + lock (_prims) + _prims[prim.LocalID] = prim; + } + + public OdePrim getPrim(uint id) + { + lock (_prims) + { + if(_prims.ContainsKey(id)) + return _prims[id]; + else + return null; + } + } + + public bool havePrim(OdePrim prm) + { + lock (_prims) + return _prims.ContainsKey(prm.LocalID); + } + + public void changePrimID(OdePrim prim,uint oldID) + { + lock (_prims) + { + if(_prims.ContainsKey(oldID)) + _prims.Remove(oldID); + _prims[prim.LocalID] = prim; + } + } + + public bool haveActor(PhysicsActor actor) + { + if (actor is OdePrim) + { + lock (_prims) + return _prims.ContainsKey(((OdePrim)actor).LocalID); + } + else if (actor is OdeCharacter) + { + lock (_characters) + return _characters.Contains((OdeCharacter)actor); + } + return false; } #endregion @@ -2254,368 +1444,126 @@ namespace OpenSim.Region.PhysicsModule.ODE #region Space Separation Calculation /// - /// Takes a space pointer and zeros out the array we're using to hold the spaces - /// - /// - private void resetSpaceArrayItemToZero(IntPtr pSpace) - { - for (int x = 0; x < staticPrimspace.GetLength(0); x++) - { - for (int y = 0; y < staticPrimspace.GetLength(1); y++) - { - if (staticPrimspace[x, y] == pSpace) - staticPrimspace[x, y] = IntPtr.Zero; - } - } - } - -// private void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY) -// { -// staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero; -// } - - /// - /// Called when a static prim moves. Allocates a space for the prim based on its position + /// Called when a static prim moves or becomes static + /// Places the prim in a space one the static sub-spaces grid /// /// the pointer to the geom that moved /// the position that the geom moved to /// a pointer to the space it was in before it was moved. /// a pointer to the new space it's in - internal IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace) + public IntPtr MoveGeomToStaticSpace(IntPtr geom, Vector3 pos, IntPtr currentspace) { - // Called from setting the Position and Size of an ODEPrim so + // moves a prim into another static sub-space or from another space into a static sub-space + + // Called ODEPrim so // it's already in locked space. - // we don't want to remove the main space - // we don't need to test physical here because this function should - // never be called if the prim is physical(active) + if (geom == IntPtr.Zero) // shouldn't happen + return IntPtr.Zero; - // All physical prim end up in the root space - //Thread.Sleep(20); - if (currentspace != space) + // get the static sub-space for current position + IntPtr newspace = calculateSpaceForGeom(pos); + + if (newspace == currentspace) // if we are there all done + return newspace; + + // else remove it from its current space + if (currentspace != IntPtr.Zero && d.SpaceQuery(currentspace, geom)) { - //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString()); - //if (currentspace == IntPtr.Zero) - //{ - //int adfadf = 0; - //} - if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero) + if (d.GeomIsSpace(currentspace)) { - if (d.GeomIsSpace(currentspace)) + waitForSpaceUnlock(currentspace); + d.SpaceRemove(currentspace, geom); + + if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0) { -// waitForSpaceUnlock(currentspace); - d.SpaceRemove(currentspace, geom); - } - else - { - m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace + - " Geom:" + geom); + d.SpaceDestroy(currentspace); } } else { - IntPtr sGeomIsIn = d.GeomGetSpace(geom); - if (sGeomIsIn != IntPtr.Zero) - { - if (d.GeomIsSpace(currentspace)) - { -// waitForSpaceUnlock(sGeomIsIn); - d.SpaceRemove(sGeomIsIn, geom); - } - else - { - m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + - sGeomIsIn + " Geom:" + geom); - } - } - } - - //If there are no more geometries in the sub-space, we don't need it in the main space anymore - if (d.SpaceGetNumGeoms(currentspace) == 0) - { - if (currentspace != IntPtr.Zero) - { - if (d.GeomIsSpace(currentspace)) - { - d.SpaceRemove(space, currentspace); - // free up memory used by the space. - - resetSpaceArrayItemToZero(currentspace); - } - else - { - m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + - currentspace + " Geom:" + geom); - } - } + m_log.Info("[Physics]: Invalid or empty Space passed to 'MoveGeomToStaticSpace':" + currentspace + + " Geom:" + geom); } } - else + else // odd currentspace is null or doesn't contain the geom? lets try the geom ideia of current space { - // this is a physical object that got disabled. ;.; - if (currentspace != IntPtr.Zero && geom != IntPtr.Zero) + currentspace = d.GeomGetSpace(geom); + if (currentspace != IntPtr.Zero) { - if (d.SpaceQuery(currentspace, geom)) + if (d.GeomIsSpace(currentspace)) { - if (d.GeomIsSpace(currentspace)) + waitForSpaceUnlock(currentspace); + d.SpaceRemove(currentspace, geom); + + if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0) { -// waitForSpaceUnlock(currentspace); - d.SpaceRemove(currentspace, geom); - } - else - { - m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + - currentspace + " Geom:" + geom); - } - } - else - { - IntPtr sGeomIsIn = d.GeomGetSpace(geom); - if (sGeomIsIn != IntPtr.Zero) - { - if (d.GeomIsSpace(sGeomIsIn)) - { -// waitForSpaceUnlock(sGeomIsIn); - d.SpaceRemove(sGeomIsIn, geom); - } - else - { - m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + - sGeomIsIn + " Geom:" + geom); - } + d.SpaceDestroy(currentspace); } + } } } - // The routines in the Position and Size sections do the 'inserting' into the space, - // so all we have to do is make sure that the space that we're putting the prim into - // is in the 'main' space. - int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos); - IntPtr newspace = calculateSpaceForGeom(pos); - - if (newspace == IntPtr.Zero) - { - newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]); - d.HashSpaceSetLevels(newspace, HashspaceLow, HashspaceHigh); - } + // put the geom in the newspace + waitForSpaceUnlock(newspace); + d.SpaceAdd(newspace, geom); + // let caller know this newspace return newspace; } - /// - /// Creates a new space at X Y - /// - /// - /// - /// A pointer to the created space - internal IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY) - { - // 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); - d.SpaceSetSublevel(space, 1); - d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]); - - return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]; - } - /// /// Calculates the space the prim should be in by its position /// /// /// a pointer to the space. This could be a new space or reused space. - internal IntPtr calculateSpaceForGeom(Vector3 pos) + public IntPtr calculateSpaceForGeom(Vector3 pos) { - int[] xyspace = calculateSpaceArrayItemFromPos(pos); - //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString()); - return staticPrimspace[xyspace[0], xyspace[1]]; + int x, y; + + if (pos.X < 0) + return staticPrimspaceOffRegion[0]; + + if (pos.Y < 0) + return staticPrimspaceOffRegion[2]; + + x = (int)(pos.X * spacesPerMeterX); + if (x > spaceGridMaxX) + return staticPrimspaceOffRegion[1]; + + y = (int)(pos.Y * spacesPerMeterY); + if (y > spaceGridMaxY) + return staticPrimspaceOffRegion[3]; + + return staticPrimspace[x, y]; } - - /// - /// Holds the space allocation logic - /// - /// - /// an array item based on the position - internal int[] calculateSpaceArrayItemFromPos(Vector3 pos) - { - int[] returnint = new int[2]; - - returnint[0] = (int) (pos.X * spacesPerMeterX); - - if (returnint[0] > spaceGridMaxX) - returnint[0] = spaceGridMaxX; - if (returnint[0] < 0) - returnint[0] = 0; - - returnint[1] = (int)(pos.Y * spacesPerMeterY); - if (returnint[1] > spaceGridMaxY) - returnint[1] = spaceGridMaxY; - if (returnint[1] < 0) - returnint[1] = 0; - - return returnint; - } - + #endregion + /// - /// Routine to figure out if we need to mesh this prim with our mesher + /// Called to queue a change to a actor + /// to use in place of old taint mechanism so changes do have a time sequence /// - /// - /// - internal bool needsMeshing(PrimitiveBaseShape pbs) + + public void AddChange(PhysicsActor actor, changes what, Object arg) { - // most of this is redundant now as the mesher will return null if it cant mesh a prim - // but we still need to check for sculptie meshing being enabled so this is the most - // convenient place to do it for now... - - // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f) - // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString()); - int iPropertiesNotSupportedDefault = 0; - - if (pbs.SculptEntry && !meshSculptedPrim) - { -#if SPAM - m_log.Warn("NonMesh"); -#endif - return false; - } - - // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim - if (!forceSimplePrimMeshing && !pbs.SculptEntry) - { - if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) - || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 - && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) - { - - if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 - && pbs.ProfileHollow == 0 - && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 - && pbs.PathBegin == 0 && pbs.PathEnd == 0 - && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 - && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 - && pbs.PathShearX == 0 && pbs.PathShearY == 0) - { -#if SPAM - m_log.Warn("NonMesh"); -#endif - return false; - } - } - } - - if (pbs.ProfileHollow != 0) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) - iPropertiesNotSupportedDefault++; - - if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100)) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0)) - iPropertiesNotSupportedDefault++; - - if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) - iPropertiesNotSupportedDefault++; - - if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X)) - iPropertiesNotSupportedDefault++; - - if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1) - iPropertiesNotSupportedDefault++; - - // test for torus - if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square) - { - if (pbs.PathCurve == (byte)Extrusion.Curve1) - { - iPropertiesNotSupportedDefault++; - } - } - else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) - { - if (pbs.PathCurve == (byte)Extrusion.Straight) - { - iPropertiesNotSupportedDefault++; - } - - // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits - else if (pbs.PathCurve == (byte)Extrusion.Curve1) - { - iPropertiesNotSupportedDefault++; - } - } - else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) - { - if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) - { - iPropertiesNotSupportedDefault++; - } - } - else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) - { - if (pbs.PathCurve == (byte)Extrusion.Straight) - { - iPropertiesNotSupportedDefault++; - } - else if (pbs.PathCurve == (byte)Extrusion.Curve1) - { - iPropertiesNotSupportedDefault++; - } - } - - if (pbs.SculptEntry && meshSculptedPrim) - iPropertiesNotSupportedDefault++; - - if (iPropertiesNotSupportedDefault == 0) - { -#if SPAM - m_log.Warn("NonMesh"); -#endif - return false; - } -#if SPAM - m_log.Debug("Mesh"); -#endif - return true; + ODEchangeitem item = new ODEchangeitem(); + item.actor = actor; + item.what = what; + item.arg = arg; + ChangesQueue.Enqueue(item); } /// /// 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 actor) + /// + /// + public override void AddPhysicsActorTaint(PhysicsActor prim) { - if (actor is OdePrim) - { - OdePrim taintedprim = ((OdePrim)actor); - lock (_taintedPrims) - _taintedPrims.Add(taintedprim); - } - else if (actor is OdeCharacter) - { - OdeCharacter taintedchar = ((OdeCharacter)actor); - lock (_taintedActors) - { - _taintedActors.Add(taintedchar); - if (taintedchar.bad) - m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid); - } - } } // does all pending changes generated during region load process @@ -2625,319 +1573,315 @@ namespace OpenSim.Region.PhysicsModule.ODE { if (world == IntPtr.Zero) { - _taintedPrims.Clear();; + ChangesQueue.Clear(); return; } - int donechanges = 0; - if (_taintedPrims.Count > 0) - { + d.AllocateODEDataForThread(~0U); - m_log.InfoFormat("[Ode] start processing pending actor operations"); + ODEchangeitem item; + + int donechanges = 0; + if (ChangesQueue.Count > 0) + { + m_log.InfoFormat("[ubOde] start processing pending actor operations"); int tstart = Util.EnvironmentTickCount(); - d.AllocateODEDataForThread(0); - - lock (_taintedPrims) + while (ChangesQueue.Dequeue(out item)) { - foreach (OdePrim prim in _taintedPrims) + if (item.actor != null) { - if (prim.m_taintremove) - RemovePrimThreadLocked(prim); - else - prim.ProcessTaints(); - - prim.m_collisionscore = 0; - donechanges++; + try + { + if (item.actor is OdeCharacter) + ((OdeCharacter)item.actor).DoAChange(item.what, item.arg); + else if (((OdePrim)item.actor).DoAChange(item.what, item.arg)) + RemovePrimThreadLocked((OdePrim)item.actor); + } + catch + { + m_log.WarnFormat("[PHYSICS]: Operation failed for a actor {0} {1}", + item.actor.Name, item.what.ToString()); + } } - _taintedPrims.Clear(); + donechanges++; } - int time = Util.EnvironmentTickCountSubtract(tstart); - m_log.InfoFormat("[Ode] finished {0} operations in {1}ms", donechanges, time); + m_log.InfoFormat("[ubOde] finished {0} operations in {1}ms", donechanges, time); } - m_log.InfoFormat("[Ode] {0} prim actors loaded",_prims.Count); + m_log.InfoFormat("[ubOde] {0} prim actors loaded",_prims.Count); } } - /// /// This is our main simulate loop - /// - /// /// It's thread locked by a Mutex in the scene. /// It holds Collisions, it instructs ODE to step through the physical reactions /// It moves the objects around in memory /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup) - /// + /// /// - /// The number of frames simulated over that period. - public override float Simulate(float timeStep) + /// + public override float Simulate(float reqTimeStep) { - if (!_worldInitialized) - return 1.0f; + DateTime now = DateTime.UtcNow; + TimeSpan timedif = now - m_lastframe; + float timeStep = (float)timedif.TotalSeconds; + m_lastframe = now; + + // acumulate time so we can reduce error + step_time += timeStep; - int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0; - int tempTick = 0, tempTick2 = 0; + if (step_time < HalfOdeStep) + return 0; - if (framecount >= int.MaxValue) + if (framecount < 0) framecount = 0; framecount++; +// checkThread(); + int nodeframes = 0; float fps = 0; - step_time += timeStep; - - float HalfOdeStep = ODE_STEPSIZE * 0.5f; - if (step_time < HalfOdeStep) - return 0; - - - // We change _collisionEventPrimChanges to avoid locking _collisionEventPrim itself and causing potential - // deadlock if the collision event tries to lock something else later on which is already locked by a - // caller that is adding or removing the collision event. - lock (m_collisionEventActorsChanges) + lock (SimulationLock) + lock(OdeLock) { - foreach (KeyValuePair kvp in m_collisionEventActorsChanges) + if (world == IntPtr.Zero) { - if (kvp.Value == null) - m_collisionEventActors.Remove(kvp.Key); - else - m_collisionEventActors[kvp.Key] = kvp.Value; + ChangesQueue.Clear(); + return 0; } - m_collisionEventActorsChanges.Clear(); - } + ODEchangeitem item; + +// d.WorldSetQuickStepNumIterations(world, curphysiteractions); - if (SupportsNINJAJoints) - { - DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks - CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks - } - - - lock (OdeLock) - { + int loopstartMS = Util.EnvironmentTickCount(); + int looptimeMS = 0; + int changestimeMS = 0; + int maxChangestime = (int)(reqTimeStep * 500f); // half the time + int maxLoopTime = (int)(reqTimeStep * 1200f); // 1.2 the time + d.AllocateODEDataForThread(~0U); + + if (ChangesQueue.Count > 0) + { + while (ChangesQueue.Dequeue(out item)) + { + if (item.actor != null) + { + try + { + if (item.actor is OdeCharacter) + ((OdeCharacter)item.actor).DoAChange(item.what, item.arg); + else if (((OdePrim)item.actor).DoAChange(item.what, item.arg)) + RemovePrimThreadLocked((OdePrim)item.actor); + } + catch + { + m_log.WarnFormat("[PHYSICS]: doChange failed for a actor {0} {1}", + item.actor.Name, item.what.ToString()); + } + } + changestimeMS = Util.EnvironmentTickCountSubtract(loopstartMS); + if (changestimeMS > maxChangestime) + break; + } + } - while (step_time > HalfOdeStep) + // do simulation taking at most 150ms total time including changes + while (step_time > HalfOdeStep) { try { - if (CollectStats) - tempTick = Util.EnvironmentTickCount(); + // clear pointer/counter to contacts to pass into joints + m_global_contactcount = 0; - lock (_taintedActors) - { - foreach (OdeCharacter character in _taintedActors) - character.ProcessTaints(); - - _taintedActors.Clear(); - } - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - - lock (_taintedPrims) - { - foreach (OdePrim prim in _taintedPrims) - { - if (prim.m_taintremove) - { -// Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name); - RemovePrimThreadLocked(prim); - } - else - { -// Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name); - prim.ProcessTaints(); - } - - prim.m_collisionscore = 0; - - // This loop can block up the Heartbeat for a very long time on large regions. - // We need to let the Watchdog know that the Heartbeat is not dead - // NOTE: This is currently commented out, but if things like OAR loading are - // timing the heartbeat out we will need to uncomment it - //Watchdog.UpdateThread(); - } - - if (SupportsNINJAJoints) - SimulatePendingNINJAJoints(); - - _taintedPrims.Clear(); - } - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } // Move characters - foreach (OdeCharacter actor in _characters) - actor.Move(defects); - - if (defects.Count != 0) + lock (_characters) { - foreach (OdeCharacter actor in defects) + List defects = new List(); + foreach (OdeCharacter actor in _characters) { - m_log.ErrorFormat( - "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when moving", - actor.Name, actor.LocalID, PhysicsSceneName); - - RemoveCharacter(actor); - actor.DestroyOdeStructures(); + if (actor != null) + actor.Move(defects); + } + if (defects.Count != 0) + { + foreach (OdeCharacter defect in defects) + { + RemoveCharacter(defect); + } + defects.Clear(); } - - defects.Clear(); - } - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; } // Move other active objects - foreach (OdePrim prim in _activeprims) + lock (_activegroups) { - prim.m_collisionscore = 0; - prim.Move(timeStep); + foreach (OdePrim aprim in _activegroups) + { + aprim.Move(); + } } - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - + m_rayCastManager.ProcessQueuedRequests(); - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - collision_optimized(); + List sleepers = new List(); - if (CollectStats) + foreach (PhysicsActor obj in _collisionEventPrim) { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - - foreach (PhysicsActor obj in m_collisionEventActors.Values) - { - // m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID); + if (obj == null) + continue; switch ((ActorTypes)obj.PhysicsActorType) { case ActorTypes.Agent: OdeCharacter cobj = (OdeCharacter)obj; - cobj.AddCollisionFrameTime(100); - cobj.SendCollisions(); + cobj.SendCollisions((int)(odetimestepMS)); break; case ActorTypes.Prim: OdePrim pobj = (OdePrim)obj; - pobj.SendCollisions(); + if (!pobj.m_outbounds) + { + pobj.SendCollisions((int)(odetimestepMS)); + if(pobj.Body != IntPtr.Zero && !pobj.m_isSelected && + !pobj.m_disabled && !pobj.m_building && + !d.BodyIsEnabled(pobj.Body)) + sleepers.Add(pobj); + } break; } } -// if (m_global_contactcount > 0) -// m_log.DebugFormat( -// "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount); + foreach(OdePrim prm in sleepers) + prm.SleeperAddCollisionEvents(); + sleepers.Clear(); - m_global_contactcount = 0; - - if (CollectStats) + lock(_collisionEventPrimRemove) { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; + foreach (PhysicsActor obj in _collisionEventPrimRemove) + _collisionEventPrim.Remove(obj); + + _collisionEventPrimRemove.Clear(); } - lock(SimulationLock) - d.WorldQuickStep(world, ODE_STEPSIZE); - - if (CollectStats) - m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); - + // do a ode simulation step + d.WorldQuickStep(world, ODE_STEPSIZE); d.JointGroupEmpty(contactgroup); + + // update managed ideia of physical data and do updates to core + /* + lock (_characters) + { + 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); + + actor.UpdatePositionAndVelocity(); + } + } + } + */ + + lock (_activegroups) + { + { + foreach (OdePrim actor in _activegroups) + { + if (actor.IsPhysical) + { + actor.UpdatePositionAndVelocity(framecount); + } + } + } + } } catch (Exception e) { - m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e); + m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e); +// ode.dunlock(world); } step_time -= ODE_STEPSIZE; - fps += ODE_STEPSIZE; + nodeframes++; + + looptimeMS = Util.EnvironmentTickCountSubtract(loopstartMS); + if (looptimeMS > maxLoopTime) + break; } - if (CollectStats) - tempTick = Util.EnvironmentTickCount(); - - foreach (OdeCharacter actor in _characters) + lock (_badCharacter) { - if (actor.bad) - m_log.ErrorFormat("[ODE SCENE]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); - - actor.UpdatePositionAndVelocity(defects); - } - - if (defects.Count != 0) - { - foreach (OdeCharacter actor in defects) + if (_badCharacter.Count > 0) { - m_log.ErrorFormat( - "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when updating position and velocity", - actor.Name, actor.LocalID, PhysicsSceneName); + foreach (OdeCharacter chr in _badCharacter) + { + RemoveCharacter(chr); + } - RemoveCharacter(actor); - actor.DestroyOdeStructures(); - } - - defects.Clear(); - } - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - - //if (timeStep < 0.2f) - - foreach (OdePrim prim in _activeprims) - { - if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag)) - { - prim.UpdatePositionAndVelocity(); - - if (SupportsNINJAJoints) - SimulateActorPendingJoints(prim); + _badCharacter.Clear(); } } - if (CollectStats) - m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); + timedif = now - m_lastMeshExpire; - //DumpJointInfo(); + if (timedif.Seconds > 10) + { + mesher.ExpireReleaseMeshs(); + m_lastMeshExpire = now; + } +// information block for in debug breakpoint only +/* + int ntopactivegeoms = d.SpaceGetNumGeoms(ActiveSpace); + int ntopstaticgeoms = d.SpaceGetNumGeoms(StaticSpace); + int ngroundgeoms = d.SpaceGetNumGeoms(GroundSpace); + + int nactivegeoms = 0; + int nactivespaces = 0; + + int nstaticgeoms = 0; + int nstaticspaces = 0; + IntPtr sp; + + for (int i = 0; i < ntopactivegeoms; i++) + { + sp = d.SpaceGetGeom(ActiveSpace, i); + if (d.GeomIsSpace(sp)) + { + nactivespaces++; + nactivegeoms += d.SpaceGetNumGeoms(sp); + } + else + nactivegeoms++; + } + + for (int i = 0; i < ntopstaticgeoms; i++) + { + sp = d.SpaceGetGeom(StaticSpace, i); + if (d.GeomIsSpace(sp)) + { + nstaticspaces++; + nstaticgeoms += d.SpaceGetNumGeoms(sp); + } + else + nstaticgeoms++; + } + + int ntopgeoms = d.SpaceGetNumGeoms(TopSpace); + + int totgeoms = nstaticgeoms + nactivegeoms + ngroundgeoms + 1; // one ray + int nbodies = d.NTotalBodies; + int ngeoms = d.NTotalGeoms; +*/ // Finished with all sim stepping. If requested, dump world state to file for debugging. // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? @@ -2956,257 +1900,30 @@ namespace OpenSim.Region.PhysicsModule.ODE d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); } + + fps = (float)nodeframes * ODE_STEPSIZE / reqTimeStep; - latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun); - - // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics - // has a max of 100 ms to run theoretically. - // If the main loop stalls, it calls Simulate later which makes the tick count ms larger. - // If Physics stalls, it takes longer which makes the tick count ms larger. - - if (latertickcount < 100) - { + if(step_time < HalfOdeStep) m_timeDilation = 1.0f; + else if (step_time > m_SkipFramesAtms) + { + // if we lag too much skip frames + m_timeDilation = 0.0f; + step_time = 0; + m_lastframe = DateTime.UtcNow; // skip also the time lost } else { - m_timeDilation = 100f / latertickcount; - //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f); + m_timeDilation = ODE_STEPSIZE / step_time; + if (m_timeDilation > 1) + m_timeDilation = 1; } - - tickCountFrameRun = Util.EnvironmentTickCount(); - - if (CollectStats) - m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick); } - fps *= 1.0f/timeStep; return fps; } /// - /// Simulate pending NINJA joints. - /// - /// - /// Called by the main Simulate() loop if NINJA joints are active. Should not be called from anywhere else. - /// - private void SimulatePendingNINJAJoints() - { - // Create pending joints, if possible - - // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating - // a joint requires specifying the body id of both involved bodies - if (pendingJoints.Count > 0) - { - List successfullyProcessedPendingJoints = new List(); - //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints"); - foreach (PhysicsJoint joint in pendingJoints) - { - //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams); - string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); - List jointBodies = new List(); - bool allJointBodiesAreReady = true; - foreach (string jointParam in jointParams) - { - if (jointParam == "NULL") - { - //DoJointErrorMessage(joint, "attaching NULL joint to world"); - jointBodies.Add(IntPtr.Zero); - } - else - { - //DoJointErrorMessage(joint, "looking for prim name: " + jointParam); - bool foundPrim = false; - lock (_prims) - { - foreach (OdePrim prim in _prims) // FIXME: inefficient - { - if (prim.SOPName == jointParam) - { - //DoJointErrorMessage(joint, "found for prim name: " + jointParam); - if (prim.IsPhysical && prim.Body != IntPtr.Zero) - { - jointBodies.Add(prim.Body); - foundPrim = true; - break; - } - else - { - DoJointErrorMessage(joint, "prim name " + jointParam + - " exists but is not (yet) physical; deferring joint creation. " + - "IsPhysical property is " + prim.IsPhysical + - " and body is " + prim.Body); - foundPrim = false; - break; - } - } - } - } - if (foundPrim) - { - // all is fine - } - else - { - allJointBodiesAreReady = false; - break; - } - } - } - - if (allJointBodiesAreReady) - { - //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams); - if (jointBodies[0] == jointBodies[1]) - { - DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams); - } - else - { - switch (joint.Type) - { - case PhysicsJointType.Ball: - { - IntPtr odeJoint; - //DoJointErrorMessage(joint, "ODE creating ball joint "); - odeJoint = d.JointCreateBall(world, IntPtr.Zero); - //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); - d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); - //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position); - d.JointSetBallAnchor(odeJoint, - joint.Position.X, - joint.Position.Y, - joint.Position.Z); - //DoJointErrorMessage(joint, "ODE joint setting OK"); - //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: "); - //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment")); - //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: "); - //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment")); - - if (joint is OdePhysicsJoint) - { - ((OdePhysicsJoint)joint).jointID = odeJoint; - } - else - { - DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); - } - } - break; - case PhysicsJointType.Hinge: - { - IntPtr odeJoint; - //DoJointErrorMessage(joint, "ODE creating hinge joint "); - odeJoint = d.JointCreateHinge(world, IntPtr.Zero); - //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); - d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); - //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position); - d.JointSetHingeAnchor(odeJoint, - joint.Position.X, - joint.Position.Y, - joint.Position.Z); - // We use the orientation of the x-axis of the joint's coordinate frame - // as the axis for the hinge. - - // Therefore, we must get the joint's coordinate frame based on the - // joint.Rotation field, which originates from the orientation of the - // joint's proxy object in the scene. - - // The joint's coordinate frame is defined as the transformation matrix - // that converts a vector from joint-local coordinates into world coordinates. - // World coordinates are defined as the XYZ coordinate system of the sim, - // as shown in the top status-bar of the viewer. - - // Once we have the joint's coordinate frame, we extract its X axis (AtAxis) - // and use that as the hinge axis. - - //joint.Rotation.Normalize(); - Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation); - - // Now extract the X axis of the joint's coordinate frame. - - // Do not try to use proxyFrame.AtAxis or you will become mired in the - // tar pit of transposed, inverted, and generally messed-up orientations. - // (In other words, Matrix4.AtAxis() is borked.) - // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness - - // Instead, compute the X axis of the coordinate frame by transforming - // the (1,0,0) vector. At least that works. - - //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame); - Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame); - //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis); - //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis); - d.JointSetHingeAxis(odeJoint, - jointAxis.X, - jointAxis.Y, - jointAxis.Z); - //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f); - if (joint is OdePhysicsJoint) - { - ((OdePhysicsJoint)joint).jointID = odeJoint; - } - else - { - DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); - } - } - break; - } - successfullyProcessedPendingJoints.Add(joint); - } - } - else - { - DoJointErrorMessage(joint, "joint could not yet be created; still pending"); - } - } - - foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints) - { - //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams); - //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending"); - InternalRemovePendingJoint(successfullyProcessedJoint); - //DoJointErrorMessage(successfullyProcessedJoint, "adding to active"); - InternalAddActiveJoint(successfullyProcessedJoint); - //DoJointErrorMessage(successfullyProcessedJoint, "done"); - } - } - } - - /// - /// Simulate the joint proxies of a NINJA actor. - /// - /// - /// Called as part of the Simulate() loop if NINJA physics is active. Must only be called from there. - /// - /// - private void SimulateActorPendingJoints(OdePrim actor) - { - // If an actor moved, move its joint proxy objects as well. - // There seems to be an event PhysicsActor.OnPositionUpdate that could be used - // for this purpose but it is never called! So we just do the joint - // movement code here. - - if (actor.SOPName != null && - joints_connecting_actor.ContainsKey(actor.SOPName) && - joints_connecting_actor[actor.SOPName] != null && - joints_connecting_actor[actor.SOPName].Count > 0) - { - foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName]) - { - if (affectedJoint.IsInPhysicsEngine) - { - DoJointMoved(affectedJoint); - } - else - { - DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams); - } - } - } - } - public override void GetResults() { } @@ -3214,33 +1931,272 @@ namespace OpenSim.Region.PhysicsModule.ODE public override bool IsThreaded { // for now we won't be multithreaded - get { return false; } + get { return (false); } } - public override void SetTerrain(float[] heightMap) + public float GetTerrainHeightAtXY(float x, float y) { - if (m_worldOffset != Vector3.Zero && m_parentScene != null) + if (TerrainGeom == IntPtr.Zero) + return 0f; + + if (TerrainHeightFieldHeight == null || TerrainHeightFieldHeight.Length == 0) + return 0f; + + // TerrainHeightField for ODE as offset 1m + x += 1f; + y += 1f; + + // make position fit into array + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + // integer indexs + int ix; + int iy; + // interpolators offset + float dx; + float dy; + + int regsizeX = (int)m_regionWidth + 3; // map size see setterrain number of samples + int regsizeY = (int)m_regionHeight + 3; // map size see setterrain number of samples + int regsize = regsizeX; + + if (m_OSOdeLib) { - if (m_parentScene is OdeScene) + if (x < regsizeX - 1) { - ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset); + ix = (int)x; + dx = x - (float)ix; + } + else // out world use external height + { + ix = regsizeX - 2; + dx = 0; + } + if (y < regsizeY - 1) + { + iy = (int)y; + dy = y - (float)iy; + } + else + { + iy = regsizeY - 2; + dy = 0; } } else { - SetTerrain(heightMap, m_worldOffset); + // we still have square fixed size regions + // also flip x and y because of how map is done for ODE fliped axis + // so ix,iy,dx and dy are inter exchanged + + regsize = regsizeY; + + if (x < regsizeX - 1) + { + iy = (int)x; + dy = x - (float)iy; + } + else // out world use external height + { + iy = regsizeX - 2; + dy = 0; + } + if (y < regsizeY - 1) + { + ix = (int)y; + dx = y - (float)ix; + } + else + { + ix = regsizeY - 2; + dx = 0; + } } + + float h0; + float h1; + float h2; + + iy *= regsize; + iy += ix; // all indexes have iy + ix + + float[] heights = TerrainHeightFieldHeight; + /* + if ((dx + dy) <= 1.0f) + { + h0 = ((float)heights[iy]); // 0,0 vertice + h1 = (((float)heights[iy + 1]) - h0) * dx; // 1,0 vertice minus 0,0 + h2 = (((float)heights[iy + regsize]) - h0) * dy; // 0,1 vertice minus 0,0 + } + else + { + h0 = ((float)heights[iy + regsize + 1]); // 1,1 vertice + h1 = (((float)heights[iy + 1]) - h0) * (1 - dy); // 1,1 vertice minus 1,0 + h2 = (((float)heights[iy + regsize]) - h0) * (1 - dx); // 1,1 vertice minus 0,1 + } + */ + h0 = ((float)heights[iy]); // 0,0 vertice + + if (dy>dx) + { + iy += regsize; + h2 = (float)heights[iy]; // 0,1 vertice + h1 = (h2 - h0) * dy; // 0,1 vertice minus 0,0 + h2 = ((float)heights[iy + 1] - h2) * dx; // 1,1 vertice minus 0,1 + } + else + { + iy++; + h2 = (float)heights[iy]; // vertice 1,0 + h1 = (h2 - h0) * dx; // 1,0 vertice minus 0,0 + h2 = (((float)heights[iy + regsize]) - h2) * dy; // 1,1 vertice minus 1,0 + } + + return h0 + h1 + h2; } - private void SetTerrain(float[] heightMap, Vector3 pOffset) + public Vector3 GetTerrainNormalAtXY(float x, float y) { - int startTime = Util.EnvironmentTickCount(); - m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0} with offset {1}", PhysicsSceneName, pOffset); + Vector3 norm = new Vector3(0, 0, 1); + + if (TerrainGeom == IntPtr.Zero) + return norm; + + if (TerrainHeightFieldHeight == null || TerrainHeightFieldHeight.Length == 0) + return norm; + + // TerrainHeightField for ODE as offset 1m + x += 1f; + y += 1f; + + // make position fit into array + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + // integer indexs + int ix; + int iy; + // interpolators offset + float dx; + float dy; + + int regsizeX = (int)m_regionWidth + 3; // map size see setterrain number of samples + int regsizeY = (int)m_regionHeight + 3; // map size see setterrain number of samples + int regsize = regsizeX; + + int xstep = 1; + int ystep = regsizeX; + bool firstTri = false; + + if (m_OSOdeLib) + { + if (x < regsizeX - 1) + { + ix = (int)x; + dx = x - (float)ix; + } + else // out world use external height + { + ix = regsizeX - 2; + dx = 0; + } + if (y < regsizeY - 1) + { + iy = (int)y; + dy = y - (float)iy; + } + else + { + iy = regsizeY - 2; + dy = 0; + } + firstTri = dy > dx; + } + + else + { + xstep = regsizeY; + ystep = 1; + regsize = regsizeY; + + // we still have square fixed size regions + // also flip x and y because of how map is done for ODE fliped axis + // so ix,iy,dx and dy are inter exchanged + if (x < regsizeX - 1) + { + iy = (int)x; + dy = x - (float)iy; + } + else // out world use external height + { + iy = regsizeX - 2; + dy = 0; + } + if (y < regsizeY - 1) + { + ix = (int)y; + dx = y - (float)ix; + } + else + { + ix = regsizeY - 2; + dx = 0; + } + firstTri = dx > dy; + } + + float h0; + float h1; + float h2; + + iy *= regsize; + iy += ix; // all indexes have iy + ix + + float[] heights = TerrainHeightFieldHeight; + + if (firstTri) + { + h1 = ((float)heights[iy]); // 0,0 vertice + iy += ystep; + h0 = (float)heights[iy]; // 0,1 + h2 = (float)heights[iy+xstep]; // 1,1 vertice + norm.X = h0 - h2; + norm.Y = h1 - h0; + } + else + { + h2 = ((float)heights[iy]); // 0,0 vertice + iy += xstep; + h0 = ((float)heights[iy]); // 1,0 vertice + h1 = (float)heights[iy+ystep]; // vertice 1,1 + norm.X = h2 - h0; + norm.Y = h0 - h1; + } + norm.Z = 1; + norm.Normalize(); + return norm; + } + + public override void SetTerrain(float[] heightMap) + { + if (m_OSOdeLib) + OSSetTerrain(heightMap); + else + OriSetTerrain(heightMap); + } + + public void OriSetTerrain(float[] heightMap) + { + // assumes 1m size grid and constante size square regions + // needs to know about sims around in future - float[] _heightmap; - // ok im lasy this are just a aliases uint regionsizeX = m_regionWidth; uint regionsizeY = m_regionHeight; @@ -3258,7 +2214,7 @@ namespace OpenSim.Region.PhysicsModule.ODE const float thickness = 10f; const int wrap = 0; - + float hfmin = float.MaxValue; float hfmax = float.MinValue; float val; @@ -3267,13 +2223,11 @@ namespace OpenSim.Region.PhysicsModule.ODE uint maxXX = regionsizeX - 1; uint maxYY = regionsizeY - 1; - // flipping map adding one margin all around so things don't fall in edges uint xt = 0; xx = 0; - for (uint x = 0; x < heightmapWidthSamples; x++) { if (x > 1 && xx < maxXX) @@ -3286,7 +2240,7 @@ namespace OpenSim.Region.PhysicsModule.ODE val = heightMap[yy + xx]; if (val < 0.0f) - val = 0.0f; + val = 0.0f; // no neg terrain as in chode _heightmap[xt + y] = val; if (hfmin > val) @@ -3301,69 +2255,164 @@ namespace OpenSim.Region.PhysicsModule.ODE { d.AllocateODEDataForThread(~0U); - IntPtr GroundGeom = IntPtr.Zero; - if (RegionTerrain.TryGetValue(pOffset, out GroundGeom)) + if (TerrainGeom != IntPtr.Zero) { - RegionTerrain.Remove(pOffset); - if (GroundGeom != IntPtr.Zero) - { - if (TerrainHeightFieldHeights.ContainsKey(GroundGeom)) - { - TerrainHeightFieldHeights.Remove(GroundGeom); - } - d.SpaceRemove(space, GroundGeom); - d.GeomDestroy(GroundGeom); - } + actor_name_map.Remove(TerrainGeom); + d.GeomDestroy(TerrainGeom); } + + if (TerrainHeightFieldHeightsHandler.IsAllocated) + TerrainHeightFieldHeightsHandler.Free(); + IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); - d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, - heightmapWidth, heightmapHeight, - (int)heightmapWidthSamples, - (int)heightmapHeightSamples, - scale, offset, thickness, wrap); + + TerrainHeightFieldHeightsHandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned); + + d.GeomHeightfieldDataBuildSingle(HeightmapData, TerrainHeightFieldHeightsHandler.AddrOfPinnedObject(), 0, + heightmapHeight, heightmapWidth , + (int)heightmapHeightSamples, (int)heightmapWidthSamples, scale, + offset, thickness, wrap); d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); - GroundGeom = d.CreateHeightfield(space, HeightmapData, 1); - if (GroundGeom != IntPtr.Zero) + + TerrainGeom = d.CreateHeightfield(GroundSpace, HeightmapData, 1); + + if (TerrainGeom != IntPtr.Zero) { - d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land)); - d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space)); + d.GeomSetCategoryBits(TerrainGeom, (uint)(CollisionCategories.Land)); + d.GeomSetCollideBits(TerrainGeom, 0); + PhysicsActor pa = new NullPhysicsActor(); + pa.Name = "Terrain"; + pa.PhysicsActorType = (int)ActorTypes.Ground; + actor_name_map[TerrainGeom] = pa; + +// geom_name_map[GroundGeom] = "Terrain"; + + d.Quaternion q = new d.Quaternion(); + q.X = 0.5f; + q.Y = 0.5f; + q.Z = 0.5f; + q.W = 0.5f; + + d.GeomSetQuaternion(TerrainGeom, ref q); + d.GeomSetPosition(TerrainGeom, m_regionWidth * 0.5f, m_regionHeight * 0.5f, 0.0f); + TerrainHeightFieldHeight = _heightmap; } - geom_name_map[GroundGeom] = "Terrain"; + else + TerrainHeightFieldHeightsHandler.Free(); + } + } - d.Matrix3 R = new d.Matrix3(); + public void OSSetTerrain(float[] heightMap) + { + // assumes 1m size grid and constante size square regions + // needs to know about sims around in future - Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); - Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f); + float[] _heightmap; - q1 = q1 * q2; - Vector3 v3; - float angle; - q1.GetAxisAngle(out v3, out angle); + uint regionsizeX = m_regionWidth; + uint regionsizeY = m_regionHeight; - d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); - d.GeomSetRotation(GroundGeom, ref R); - d.GeomSetPosition(GroundGeom, pOffset.X + regionsizeX * 0.5f, pOffset.Y + regionsizeY * 0.5f, 0.0f); - IntPtr testGround = IntPtr.Zero; - if (RegionTerrain.TryGetValue(pOffset, out testGround)) + uint heightmapWidth = regionsizeX + 2; + uint heightmapHeight = regionsizeY + 2; + + uint heightmapWidthSamples = heightmapWidth + 1; + uint heightmapHeightSamples = heightmapHeight + 1; + + _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples]; + + + float hfmin = float.MaxValue; +// float hfmax = float.MinValue; + float val; + + + uint maxXX = regionsizeX - 1; + uint maxYY = regionsizeY - 1; + // adding one margin all around so things don't fall in edges + + uint xx; + uint yy = 0; + uint yt = 0; + + for (uint y = 0; y < heightmapHeightSamples; y++) + { + if (y > 1 && y < maxYY) + yy += regionsizeX; + xx = 0; + for (uint x = 0; x < heightmapWidthSamples; x++) { - RegionTerrain.Remove(pOffset); + if (x > 1 && x < maxXX) + xx++; + + val = heightMap[yy + xx]; + if (val < 0.0f) + val = 0.0f; // no neg terrain as in chode + _heightmap[yt + x] = val; + + if (hfmin > val) + hfmin = val; +// if (hfmax < val) +// hfmax = val; } - RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); - TerrainHeightFieldHeights.Add(GroundGeom,_heightmap); + yt += heightmapWidthSamples; } - m_log.DebugFormat( - "[ODE SCENE]: Setting terrain for {0} took {1}ms", PhysicsSceneName, Util.EnvironmentTickCountSubtract(startTime)); + lock (OdeLock) + { + if (TerrainGeom != IntPtr.Zero) + { + actor_name_map.Remove(TerrainGeom); + d.GeomDestroy(TerrainGeom); + } + + if (TerrainHeightFieldHeightsHandler.IsAllocated) + TerrainHeightFieldHeightsHandler.Free(); + + TerrainHeightFieldHeight = null; + + IntPtr HeightmapData = d.GeomOSTerrainDataCreate(); + + const int wrap = 0; + float thickness = hfmin; + if (thickness < 0) + thickness = 1; + + TerrainHeightFieldHeightsHandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned); + + d.GeomOSTerrainDataBuild(HeightmapData, TerrainHeightFieldHeightsHandler.AddrOfPinnedObject(), 0, 1.0f, + (int)heightmapWidthSamples, (int)heightmapHeightSamples, + thickness, wrap); + +// d.GeomOSTerrainDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); + TerrainGeom = d.CreateOSTerrain(GroundSpace, HeightmapData, 1); + if (TerrainGeom != IntPtr.Zero) + { + d.GeomSetCategoryBits(TerrainGeom, (uint)(CollisionCategories.Land)); + d.GeomSetCollideBits(TerrainGeom, 0); + + PhysicsActor pa = new NullPhysicsActor(); + pa.Name = "Terrain"; + pa.PhysicsActorType = (int)ActorTypes.Ground; + actor_name_map[TerrainGeom] = pa; + +// geom_name_map[GroundGeom] = "Terrain"; + + d.GeomSetPosition(TerrainGeom, m_regionWidth * 0.5f, m_regionHeight * 0.5f, 0.0f); + TerrainHeightFieldHeight = _heightmap; + } + else + TerrainHeightFieldHeightsHandler.Free(); + } } public override void DeleteTerrain() { } - internal float GetWaterLevel() + public float GetWaterLevel() { return waterlevel; } @@ -3373,19 +2422,19 @@ namespace OpenSim.Region.PhysicsModule.ODE waterlevel = baseheight; } - [HandleProcessCorruptedStateExceptions] public override void Dispose() { - lock(SimulationLock) - lock(OdeLock) + lock (OdeLock) { - if(world == IntPtr.Zero) + + if (world == IntPtr.Zero) return; - _worldInitialized = false; - d.AllocateODEDataForThread(~0U); + if (m_meshWorker != null) + m_meshWorker.Stop(); + if (m_rayCastManager != null) { m_rayCastManager.Dispose(); @@ -3394,37 +2443,49 @@ namespace OpenSim.Region.PhysicsModule.ODE lock (_prims) { - foreach (OdePrim prm in _prims) + ChangesQueue.Clear(); + foreach (OdePrim prm in _prims.Values) { - RemovePrim(prm); + prm.DoAChange(changes.Remove, null); + _collisionEventPrim.Remove(prm); } + _prims.Clear(); } - //foreach (OdeCharacter act in _characters) - //{ - //RemoveAvatar(act); - //} - IntPtr GroundGeom = IntPtr.Zero; - if (RegionTerrain.TryGetValue(m_worldOffset, out GroundGeom)) + OdeCharacter[] chtorem; + lock (_characters) { - RegionTerrain.Remove(m_worldOffset); - if (GroundGeom != IntPtr.Zero) - { - if (TerrainHeightFieldHeights.ContainsKey(GroundGeom)) - TerrainHeightFieldHeights.Remove(GroundGeom); - d.GeomDestroy(GroundGeom); - } - } + chtorem = new OdeCharacter[_characters.Count]; + _characters.CopyTo(chtorem); + } - try + ChangesQueue.Clear(); + foreach (OdeCharacter ch in chtorem) + ch.DoAChange(changes.Remove, null); + + if (TerrainGeom != IntPtr.Zero) + d.GeomDestroy(TerrainGeom); + TerrainGeom = IntPtr.Zero; + + if (TerrainHeightFieldHeightsHandler.IsAllocated) + TerrainHeightFieldHeightsHandler.Free(); + + TerrainHeightFieldHeight = null; + + if (ContactgeomsArray != IntPtr.Zero) { - d.WorldDestroy(world); - world = IntPtr.Zero; + Marshal.FreeHGlobal(ContactgeomsArray); + ContactgeomsArray = IntPtr.Zero; } - catch (AccessViolationException e) + if (GlobalContactsArray != IntPtr.Zero) { - m_log.ErrorFormat("[ODE SCENE]: exception {0}", e.Message); + Marshal.FreeHGlobal(GlobalContactsArray); + GlobalContactsArray = IntPtr.Zero; } + + d.WorldDestroy(world); + world = IntPtr.Zero; + //d.CloseODE(); } } @@ -3436,17 +2497,13 @@ namespace OpenSim.Region.PhysicsModule.ODE public override Dictionary GetTopColliders() { Dictionary topColliders; + List orderedPrims; + lock (_activeprims) + orderedPrims = new List(_activeprims); - lock (_prims) - { - List orderedPrims = new List(_prims); - orderedPrims.Sort(compareByCollisionsDesc); - topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore); - - foreach (OdePrim p in _prims) - p.CollisionScore = 0; - } - + orderedPrims.Sort(compareByCollisionsDesc); + topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore); + return topColliders; } @@ -3459,7 +2516,16 @@ namespace OpenSim.Region.PhysicsModule.ODE { if (retMethod != null) { - m_rayCastManager.QueueRequest(position, direction, length, retMethod); + ODERayRequest req = new ODERayRequest(); + req.actor = null; + req.callbackMethod = retMethod; + req.length = length; + req.Normal = direction; + req.Origin = position; + req.Count = 0; + req.filter = RayFilterFlags.AllPrims; + + m_rayCastManager.QueueRequest(req); } } @@ -3467,75 +2533,260 @@ namespace OpenSim.Region.PhysicsModule.ODE { if (retMethod != null) { - m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); + ODERayRequest req = new ODERayRequest(); + req.actor = null; + req.callbackMethod = retMethod; + req.length = length; + req.Normal = direction; + req.Origin = position; + req.Count = Count; + req.filter = RayFilterFlags.AllPrims; + + m_rayCastManager.QueueRequest(req); } } + public override List RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) { - ContactResult[] ourResults = null; + List ourresults = new List(); + object SyncObject = new object(); + RayCallback retMethod = delegate(List results) { - ourResults = new ContactResult[results.Count]; - results.CopyTo(ourResults, 0); + lock (SyncObject) + { + ourresults = results; + Monitor.PulseAll(SyncObject); + } }; - int waitTime = 0; - m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); - while (ourResults == null && waitTime < 1000) + + ODERayRequest req = new ODERayRequest(); + req.actor = null; + req.callbackMethod = retMethod; + req.length = length; + req.Normal = direction; + req.Origin = position; + req.Count = Count; + req.filter = RayFilterFlags.AllPrims; + + lock (SyncObject) { - Thread.Sleep(1); - waitTime++; + m_rayCastManager.QueueRequest(req); + if (!Monitor.Wait(SyncObject, 500)) + return null; + else + return ourresults; } + } + + public override bool SupportsRaycastWorldFiltered() + { + return true; + } + + public override object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter) + { + object SyncObject = new object(); + List ourresults = new List(); + + RayCallback retMethod = delegate(List results) + { + lock (SyncObject) + { + ourresults = results; + Monitor.PulseAll(SyncObject); + } + }; + + ODERayRequest req = new ODERayRequest(); + req.actor = null; + req.callbackMethod = retMethod; + req.length = length; + req.Normal = direction; + req.Origin = position; + req.Count = Count; + req.filter = filter; + + lock (SyncObject) + { + m_rayCastManager.QueueRequest(req); + if (!Monitor.Wait(SyncObject, 500)) + return null; + else + return ourresults; + } + } + + public override List RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags flags) + { + if (actor == null) + return new List(); + + IntPtr geom; + if (actor is OdePrim) + geom = ((OdePrim)actor).prim_geom; + else if (actor is OdeCharacter) + geom = ((OdePrim)actor).prim_geom; + else + return new List(); + + if (geom == IntPtr.Zero) + return new List(); + + List ourResults = null; + object SyncObject = new object(); + + RayCallback retMethod = delegate(List results) + { + lock (SyncObject) + { + ourResults = results; + Monitor.PulseAll(SyncObject); + } + }; + + ODERayRequest req = new ODERayRequest(); + req.actor = actor; + req.callbackMethod = retMethod; + req.length = length; + req.Normal = direction; + req.Origin = position; + req.Count = Count; + req.filter = flags; + + lock (SyncObject) + { + m_rayCastManager.QueueRequest(req); + if (!Monitor.Wait(SyncObject, 500)) + return new List(); + } + if (ourResults == null) - return new List (); - return new List(ourResults); + return new List(); + return ourResults; } - public override Dictionary GetStats() + public override List BoxProbe(Vector3 position, Vector3 size, Quaternion orientation, int Count, RayFilterFlags flags) { - if (!CollectStats) - return null; + List ourResults = null; + object SyncObject = new object(); - Dictionary returnStats; - - lock (OdeLock) + ProbeBoxCallback retMethod = delegate(List results) { - returnStats = new Dictionary(m_stats); + lock (SyncObject) + { + ourResults = results; + Monitor.PulseAll(SyncObject); + } + }; - // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by - // 3 from the SimStatsReporter. - returnStats[ODETotalAvatarsStatName] = _characters.Count * 3; - returnStats[ODETotalPrimsStatName] = _prims.Count * 3; - returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3; + ODERayRequest req = new ODERayRequest(); + req.actor = null; + req.callbackMethod = retMethod; + req.Normal = size; + req.Origin = position; + req.orientation = orientation; + req.Count = Count; + req.filter = flags; - InitializeExtraStats(); + lock (SyncObject) + { + m_rayCastManager.QueueRequest(req); + if (!Monitor.Wait(SyncObject, 500)) + return new List(); } - returnStats[ODEOtherCollisionFrameMsStatName] - = returnStats[ODEOtherCollisionFrameMsStatName] - - returnStats[ODENativeSpaceCollisionFrameMsStatName] - - returnStats[ODENativeGeomCollisionFrameMsStatName]; - - return returnStats; + if (ourResults == null) + return new List(); + return ourResults; } - private void InitializeExtraStats() + public override List SphereProbe(Vector3 position, float radius, int Count, RayFilterFlags flags) { - m_stats[ODETotalFrameMsStatName] = 0; - m_stats[ODEAvatarTaintMsStatName] = 0; - m_stats[ODEPrimTaintMsStatName] = 0; - m_stats[ODEAvatarForcesFrameMsStatName] = 0; - m_stats[ODEPrimForcesFrameMsStatName] = 0; - m_stats[ODERaycastingFrameMsStatName] = 0; - m_stats[ODENativeStepFrameMsStatName] = 0; - m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0; - m_stats[ODENativeGeomCollisionFrameMsStatName] = 0; - m_stats[ODEOtherCollisionFrameMsStatName] = 0; - m_stats[ODECollisionNotificationFrameMsStatName] = 0; - m_stats[ODEAvatarContactsStatsName] = 0; - m_stats[ODEPrimContactsStatName] = 0; - m_stats[ODEAvatarUpdateFrameMsStatName] = 0; - m_stats[ODEPrimUpdateFrameMsStatName] = 0; + List ourResults = null; + object SyncObject = new object(); + + ProbeSphereCallback retMethod = delegate(List results) + { + ourResults = results; + Monitor.PulseAll(SyncObject); + }; + + ODERayRequest req = new ODERayRequest(); + req.actor = null; + req.callbackMethod = retMethod; + req.length = radius; + req.Origin = position; + req.Count = Count; + req.filter = flags; + + + lock (SyncObject) + { + m_rayCastManager.QueueRequest(req); + if (!Monitor.Wait(SyncObject, 500)) + return new List(); + } + + if (ourResults == null) + return new List(); + return ourResults; } + + public override List PlaneProbe(PhysicsActor actor, Vector4 plane, int Count, RayFilterFlags flags) + { + IntPtr geom = IntPtr.Zero;; + + if (actor != null) + { + if (actor is OdePrim) + geom = ((OdePrim)actor).prim_geom; + else if (actor is OdeCharacter) + geom = ((OdePrim)actor).prim_geom; + } + + List ourResults = null; + object SyncObject = new object(); + + ProbePlaneCallback retMethod = delegate(List results) + { + ourResults = results; + Monitor.PulseAll(SyncObject); + }; + + ODERayRequest req = new ODERayRequest(); + req.actor = null; + req.callbackMethod = retMethod; + req.length = plane.W; + req.Normal.X = plane.X; + req.Normal.Y = plane.Y; + req.Normal.Z = plane.Z; + req.Count = Count; + req.filter = flags; + + lock (SyncObject) + { + m_rayCastManager.QueueRequest(req); + if (!Monitor.Wait(SyncObject, 500)) + return new List(); + } + + if (ourResults == null) + return new List(); + return ourResults; + } + + public override int SitAvatar(PhysicsActor actor, Vector3 AbsolutePosition, Vector3 CameraPosition, Vector3 offset, Vector3 AvatarSize, SitAvatarCallback PhysicsSitResponse) + { + Util.FireAndForget( delegate + { + ODESitAvatar sitAvatar = new ODESitAvatar(this, m_rayCastManager); + if(sitAvatar != null) + sitAvatar.Sit(actor, AbsolutePosition, CameraPosition, offset, AvatarSize, PhysicsSitResponse); + }); + return 1; + } + } } From 1507c5230bdac908ebba267ed7e8169e4ee8ab74 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 30 Dec 2016 05:13:53 +0000 Subject: [PATCH 232/305] remove a gc.collect that isn't very usefull (on the right engine this time) --- OpenSim/Region/PhysicsModules/Ode/OdeScene.cs | 4663 ++++++++++------- .../Region/PhysicsModules/ubOde/ODEScene.cs | 2 - 2 files changed, 2706 insertions(+), 1959 deletions(-) diff --git a/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs index 410463c77a..ed2aad424e 100644 --- a/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs +++ b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs @@ -25,54 +25,52 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Revision 2011/12/13 by Ubit Umarov -//#define SPAM +// changes for varsize regions +// note that raycasts need to have limited range +// (even in normal regions) +// or application thread stack may just blowup +// see RayCast(ODERayCastRequest req) using System; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Threading; -using System.IO; -using System.Diagnostics; using log4net; using Nini.Config; using Mono.Addins; -using OdeAPI; +using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.PhysicsModules.SharedBase; -using OpenMetaverse; -namespace OpenSim.Region.PhysicsModule.ubOde +namespace OpenSim.Region.PhysicsModule.ODE { - // colision flags of things others can colide with - // rays, sensors, probes removed since can't be colided with - // The top space where things are placed provided further selection - // ie physical are in active space nonphysical in static - // this should be exclusive as possible + public enum StatusIndicators : int + { + Generic = 0, + Start = 1, + End = 2 + } [Flags] - public enum CollisionCategories : uint + public enum CollisionCategories : int { Disabled = 0, - //by 'things' types - Space = 0x01, - Geom = 0x02, // aka prim/part - Character = 0x04, - Land = 0x08, - Water = 0x010, - - // by state - Phantom = 0x01000, - VolumeDtc = 0x02000, - Selected = 0x04000, - NoShape = 0x08000, - - - All = 0xffffffff + Geom = 0x00000001, + Body = 0x00000002, + Space = 0x00000004, + Character = 0x00000008, + Land = 0x00000010, + Water = 0x00000020, + Wind = 0x00000040, + Sensor = 0x00000080, + Selected = 0x00000100 } /// @@ -93,579 +91,836 @@ namespace OpenSim.Region.PhysicsModule.ubOde /// Plastic = 5, /// - Rubber = 6, - - light = 7 // compatibility with old viewers - } - - public enum changes : int - { - Add = 0, // arg null. finishs the prim creation. should be used internally only ( to remove later ?) - Remove, - Link, // arg AuroraODEPrim new parent prim or null to delink. Makes the prim part of a object with prim parent as root - // or removes from a object if arg is null - DeLink, - Position, // arg Vector3 new position in world coords. Changes prim position. Prim must know if it is root or child - Orientation, // arg Quaternion new orientation in world coords. Changes prim position. Prim must know it it is root or child - PosOffset, // not in use - // arg Vector3 new position in local coords. Changes prim position in object - OriOffset, // not in use - // arg Vector3 new position in local coords. Changes prim position in object - Velocity, - TargetVelocity, - AngVelocity, - Acceleration, - Force, - Torque, - Momentum, - - AddForce, - AddAngForce, - AngLock, - - Buoyancy, - - PIDTarget, - PIDTau, - PIDActive, - - PIDHoverHeight, - PIDHoverType, - PIDHoverTau, - PIDHoverActive, - - Size, - AvatarSize, - Shape, - PhysRepData, - AddPhysRep, - - CollidesWater, - VolumeDtc, - - Physical, - Phantom, - Selected, - disabled, - building, - - VehicleType, - VehicleFloatParam, - VehicleVectorParam, - VehicleRotationParam, - VehicleFlags, - SetVehicle, - - Null //keep this last used do dim the methods array. does nothing but pulsing the prim + Rubber = 6 } - public struct ODEchangeitem + public class OdeScene : PhysicsScene { - public PhysicsActor actor; - public OdeCharacter character; - public changes what; - public Object arg; - } + private readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString()); - public class ODEScene : PhysicsScene - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + // private Dictionary m_storedCollisions = new Dictionary(); - public bool m_OSOdeLib = false; - public Scene m_frameWorkScene = null; - -// private int threadid = 0; - -// const d.ContactFlags comumContactFlags = d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM |d.ContactFlags.Approx1 | d.ContactFlags.Bounce; - - const d.ContactFlags comumContactFlags = d.ContactFlags.Bounce | d.ContactFlags.Approx1 | d.ContactFlags.Slip1 | d.ContactFlags.Slip2; - const float comumContactERP = 0.75f; - const float comumContactCFM = 0.0001f; - const float comumContactSLIP = 0f; + /// + /// Provide a sync object so that only one thread calls d.Collide() at a time across all OdeScene instances. + /// + /// + /// With ODE as of r1755 (though also tested on r1860), only one thread can call d.Collide() at a + /// time, even where physics objects are in entirely different ODE worlds. This is because generating contacts + /// uses a static cache at the ODE level. + /// + /// Without locking, simulators running multiple regions will eventually crash with a native stack trace similar + /// to + /// + /// mono() [0x489171] + /// mono() [0x4d154f] + /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f6ded592c60] + /// .../opensim/bin/libode-x86_64.so(_ZN6Opcode11OBBCollider8_CollideEPKNS_14AABBNoLeafNodeE+0xd7a) [0x7f6dd822628a] + /// + /// ODE provides an experimental option to cache in thread local storage but compiling ODE with this option + /// causes OpenSimulator to immediately crash with a native stack trace similar to + /// + /// mono() [0x489171] + /// mono() [0x4d154f] + /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f03c9849c60] + /// .../opensim/bin/libode-x86_64.so(_Z12dCollideCCTLP6dxGeomS0_iP12dContactGeomi+0x92) [0x7f03b44bcf82] + /// + internal static Object UniversalColliderSyncObject = new Object(); + internal static Object SimulationLock = new Object(); - float frictionMovementMult = 0.8f; + /// + /// Is stats collecting enabled for this ODE scene? + /// + public bool CollectStats { get; set; } - float TerrainBounce = 0.1f; - float TerrainFriction = 0.3f; + /// + /// Statistics for this scene. + /// + private Dictionary m_stats = new Dictionary(); - public float AvatarFriction = 0;// 0.9f * 0.5f; + /// + /// Stat name for total number of avatars in this ODE scene. + /// + public const string ODETotalAvatarsStatName = "ODETotalAvatars"; + + /// + /// Stat name for total number of prims in this ODE scene. + /// + public const string ODETotalPrimsStatName = "ODETotalPrims"; + + /// + /// Stat name for total number of prims with active physics in this ODE scene. + /// + public const string ODEActivePrimsStatName = "ODEActivePrims"; + + /// + /// Stat name for the total time spent in ODE frame processing. + /// + /// + /// A sanity check for the main scene loop physics time. + /// + public const string ODETotalFrameMsStatName = "ODETotalFrameMS"; + + /// + /// Stat name for time spent processing avatar taints per frame + /// + public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS"; + + /// + /// Stat name for time spent processing prim taints per frame + /// + public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS"; + + /// + /// Stat name for time spent calculating avatar forces per frame. + /// + public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS"; + + /// + /// Stat name for time spent calculating prim forces per frame + /// + public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS"; + + /// + /// Stat name for time spent fulfilling raycasting requests per frame + /// + public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS"; + + /// + /// Stat name for time spent in native code that actually steps through the simulation. + /// + public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS"; + + /// + /// Stat name for the number of milliseconds that ODE spends in native space collision code. + /// + public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS"; + + /// + /// Stat name for milliseconds that ODE spends in native geom collision code. + /// + public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS"; + + /// + /// Time spent in collision processing that is not spent in native space or geom collision code. + /// + public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS"; + + /// + /// Stat name for time spent notifying listeners of collisions + /// + public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS"; + + /// + /// Stat name for milliseconds spent updating avatar position and velocity + /// + public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS"; + + /// + /// Stat name for the milliseconds spent updating prim position and velocity + /// + public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS"; + + /// + /// Stat name for avatar collisions with another entity. + /// + public const string ODEAvatarContactsStatsName = "ODEAvatarContacts"; + + /// + /// Stat name for prim collisions with another entity. + /// + public const string ODEPrimContactsStatName = "ODEPrimContacts"; + + /// + /// Used to hold tick numbers for stat collection purposes. + /// + private int m_nativeCollisionStartTick; + + /// + /// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback. + /// + private bool m_inCollisionTiming; + + /// + /// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object + /// collisions occured using the _perloopcontact if stats collection is enabled. + /// + private int m_tempAvatarCollisionsThisFrame; + + /// + /// Used in calculating physics frame time dilation + /// + private int tickCountFrameRun; + + /// + /// Used in calculating physics frame time dilation + /// + private int latertickcount; + + private Random fluidRandomizer = new Random(Environment.TickCount); - // this netx dimensions are only relevant for terrain partition (mega regions) - // WorldExtents below has the simulation dimensions - // they should be identical except on mega regions private uint m_regionWidth = Constants.RegionSize; private uint m_regionHeight = Constants.RegionSize; - public float ODE_STEPSIZE = 0.020f; - public float HalfOdeStep = 0.01f; - public int odetimestepMS = 20; // rounded - private float metersInSpace = 25.6f; + private float ODE_STEPSIZE = 0.0178f; + private float metersInSpace = 29.9f; private float m_timeDilation = 1.0f; - private DateTime m_lastframe; - private DateTime m_lastMeshExpire; - public float gravityx = 0f; public float gravityy = 0f; public float gravityz = -9.8f; + public float AvatarTerminalVelocity { get; set; } + + private float contactsurfacelayer = 0.001f; + + private int HashspaceLow = -5; + private int HashspaceHigh = 12; + private float waterlevel = 0f; private int framecount = 0; + //private int m_returncollisions = 10; + + private IntPtr contactgroup; + +// internal IntPtr WaterGeom; + + private float nmTerrainContactFriction = 255.0f; + private float nmTerrainContactBounce = 0.1f; + private float nmTerrainContactERP = 0.1025f; + + private float mTerrainContactFriction = 75f; + private float mTerrainContactBounce = 0.1f; + private float mTerrainContactERP = 0.05025f; + + private float nmAvatarObjectContactFriction = 250f; + private float nmAvatarObjectContactBounce = 0.1f; + + private float mAvatarObjectContactFriction = 75f; + private float mAvatarObjectContactBounce = 0.1f; + + private float avPIDD = 3200f; + private float avPIDP = 1400f; + private float avCapRadius = 0.37f; + private float avStandupTensor = 2000000f; + + /// + /// true = old compatibility mode with leaning capsule; false = new corrected mode + /// + /// + /// Even when set to false, the capsule still tilts but this is done in a different way. + /// + public bool IsAvCapsuleTilted { get; private set; } private float avDensity = 80f; private float avMovementDivisorWalk = 1.3f; private float avMovementDivisorRun = 0.8f; private float minimumGroundFlightOffset = 3f; public float maximumMassObject = 10000.01f; - public float geomDefaultDensity = 10.0f; - public float maximumAngularVelocity = 12.0f; // default 12rad/s - public float maxAngVelocitySQ = 144f; // squared value + public bool meshSculptedPrim = true; + public bool forceSimplePrimMeshing = false; + + public float meshSculptLOD = 32; + public float MeshSculptphysicalLOD = 16; + + public float geomDefaultDensity = 10.000006836f; + + public int geomContactPointsStartthrottle = 3; + public int geomUpdatesPerThrottledUpdate = 15; + private const int avatarExpectedContacts = 3; public float bodyPIDD = 35f; public float bodyPIDG = 25; - public int bodyFramesAutoDisable = 5; + public int bodyFramesAutoDisable = 20; + + private bool m_filterCollisions = true; private d.NearCallback nearCallback; - - private Dictionary _prims = new Dictionary(); - private HashSet _characters = new HashSet(); - private HashSet _activeprims = new HashSet(); - private HashSet _activegroups = new HashSet(); - - public OpenSim.Framework.LocklessQueue ChangesQueue = new OpenSim.Framework.LocklessQueue(); + public d.TriCallback triCallback; + public d.TriArrayCallback triArrayCallback; /// - /// A list of actors that should receive collision events. + /// Avatars in the physics scene. /// - private List _collisionEventPrim = new List(); - private List _collisionEventPrimRemove = new List(); - - private HashSet _badCharacter = new HashSet(); + 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(); + + /// + /// Prims that the simulator has created/deleted/updated and so need updating in ODE. + /// + private readonly HashSet _taintedPrims = 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(); + + /// + /// A dictionary of actors that should receive collision events. + /// + private readonly Dictionary m_collisionEventActors = new Dictionary(); + + /// + /// A dictionary of collision event changes that are waiting to be processed. + /// + private readonly Dictionary m_collisionEventActorsChanges = new Dictionary(); + + /// + /// Maps a unique geometry id (a memory location) to a physics actor name. + /// + /// + /// 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(); + + /// + /// 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 float contactsurfacelayer = 0.002f; + /// + /// 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 int contactsPerCollision = 80; - internal IntPtr ContactgeomsArray = IntPtr.Zero; - private IntPtr GlobalContactsArray = IntPtr.Zero; - private d.Contact SharedTmpcontact = new d.Contact(); + private bool m_NINJA_physics_joints_enabled = false; + //private Dictionary jointpart_name_map = new Dictionary(); + private readonly Dictionary> joints_connecting_actor = new Dictionary>(); + private d.ContactGeom[] contacts; - const int maxContactsbeforedeath = 6000; - private volatile int m_global_contactcount = 0; + /// + /// 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(); - private IntPtr contactgroup; + /// + /// can lock for longer. accessed only by OdeScene. + /// + private readonly List pendingJoints = new List(); - public ContactData[] m_materialContactsData = new ContactData[8]; + /// + /// can lock for longer. accessed only by OdeScene. + /// + private readonly List activeJoints = new List(); - private IntPtr TerrainGeom; - private float[] TerrainHeightFieldHeight; - private GCHandle TerrainHeightFieldHeightsHandler = new GCHandle(); - - private int m_physicsiterations = 15; + /// + /// 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(); + private readonly DoubleDictionary RegionTerrain = new DoubleDictionary(); + private readonly Dictionary TerrainHeightFieldHeights = new Dictionary(); + + private d.Contact contact; + private d.Contact TerrainContact; + private d.Contact AvatarMovementprimContact; + private d.Contact AvatarMovementTerrainContact; + private d.Contact WaterContact; + private d.Contact[,] m_materialContacts; + + private int m_physicsiterations = 10; private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag -// private PhysicsActor PANull = new NullPhysicsActor(); + private readonly PhysicsActor PANull = new NullPhysicsActor(); private float step_time = 0.0f; - public IntPtr world; + private uint obj2LocalID = 0; + private OdeCharacter cc1; + private OdePrim cp1; + private OdeCharacter cc2; + private OdePrim cp2; + private int p1ExpectedPoints = 0; + private int p2ExpectedPoints = 0; - // split the spaces acording to contents type - // ActiveSpace contains characters and active prims - // StaticSpace contains land and other that is mostly static in enviroment - // this can contain subspaces, like the grid in staticspace - // as now space only contains this 2 top spaces + public IntPtr space; - public IntPtr TopSpace; // the global space - public IntPtr ActiveSpace; // space for active prims - public IntPtr CharsSpace; // space for active prims - public IntPtr StaticSpace; // space for the static things around - public IntPtr GroundSpace; // space for ground + // split static geometry collision handling into spaces of 30 meters + public IntPtr[,] staticPrimspace; - // some speedup variables - private int spaceGridMaxX; - private int spaceGridMaxY; - private float spacesPerMeterX; - private float spacesPerMeterY; + /// + /// Used to lock the entire physics scene. Locked during the main part of Simulate() + /// + internal Object OdeLock = new Object(); - // split static geometry collision into a grid as before - private IntPtr[,] staticPrimspace; - private IntPtr[] staticPrimspaceOffRegion; - - public Object OdeLock; - public static Object SimulationLock; + private bool _worldInitialized = false; public IMesher mesher; - public IConfigSource m_config; + private IConfigSource m_config; public bool physics_logging = false; public int physics_logging_interval = 0; public bool physics_logging_append_existing_logfile = false; + private bool avplanted = false; + private bool av_av_collisions_off = false; + + public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); + public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); + + private volatile int m_global_contactcount = 0; + + private Vector3 m_worldOffset = Vector3.Zero; public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); + private PhysicsScene m_parentScene = null; + + float spacesPerMeterX; + float spacesPerMeterY; + int spaceGridMaxX; + int spaceGridMaxY; private ODERayCastRequestManager m_rayCastManager; - public ODEMeshWorker m_meshWorker; - - /* maybe needed if ode uses tls - private void checkThread() - { - - int th = Thread.CurrentThread.ManagedThreadId; - if(th != threadid) - { - threadid = th; - d.AllocateODEDataForThread(~0U); - } - } - */ - - IConfig physicsconfig = null; - - public ODEScene(Scene pscene, IConfigSource psourceconfig, string pname, string pversion, bool pOSOdeLib) - { - OdeLock = new Object(); + + public Scene m_frameWorkScene = null; + public OdeScene(Scene pscene, IConfigSource psourceconfig, string pname, string pversion) + { + m_config = psourceconfig; + m_frameWorkScene = pscene; + EngineType = pname; PhysicsSceneName = EngineType + "/" + pscene.RegionInfo.RegionName; EngineName = pname + " " + pversion; - m_config = psourceconfig; - m_OSOdeLib = pOSOdeLib; -// m_OSOdeLib = false; //debug + pscene.RegisterModuleInterface(this); + Vector3 extent = new Vector3(pscene.RegionInfo.RegionSizeX, pscene.RegionInfo.RegionSizeY, pscene.RegionInfo.RegionSizeZ); + Initialise(extent); + InitialiseFromConfig(m_config); - m_frameWorkScene = pscene; + // This may not be that good since terrain may not be avaiable at this point + base.Initialise(pscene.PhysicsRequestAsset, + (pscene.Heightmap != null ? pscene.Heightmap.GetFloatsSerialised() : new float[(int)(extent.X * extent.Y)]), + (float)pscene.RegionInfo.RegionSettings.WaterHeight); - m_frameWorkScene.RegisterModuleInterface(this); - - Initialization(); - - base.Initialise(m_frameWorkScene.PhysicsRequestAsset, - (m_frameWorkScene.Heightmap != null ? m_frameWorkScene.Heightmap.GetFloatsSerialised() : new float[m_frameWorkScene.RegionInfo.RegionSizeX * m_frameWorkScene.RegionInfo.RegionSizeY]), - (float)m_frameWorkScene.RegionInfo.RegionSettings.WaterHeight); } - public void RegionLoaded() + public void RegionLoaded() { mesher = m_frameWorkScene.RequestModuleInterface(); if (mesher == null) - { - m_log.ErrorFormat("[ubOde] No mesher. module disabled"); - return; - } - - m_meshWorker = new ODEMeshWorker(this, m_log, mesher, physicsconfig); - m_frameWorkScene.PhysicsEnabled = true; + m_log.WarnFormat("[ODE SCENE]: No mesher in {0}. Things will not work well.", PhysicsSceneName); + + m_frameWorkScene.PhysicsEnabled = true; } + /// /// Initiailizes the scene /// Sets many properties that ODE requires to be stable /// These settings need to be tweaked 'exactly' right or weird stuff happens. /// - private void Initialization() + private void Initialise(Vector3 regionExtent) { - d.AllocateODEDataForThread(~0U); - - SimulationLock = new Object(); - + WorldExtents.X = regionExtent.X; + m_regionWidth = (uint)regionExtent.X; + WorldExtents.Y = regionExtent.Y; + m_regionHeight = (uint)regionExtent.Y; + nearCallback = near; - m_rayCastManager = new ODERayCastRequestManager(this); - WorldExtents.X = m_frameWorkScene.RegionInfo.RegionSizeX; - m_regionWidth = (uint)WorldExtents.X; - WorldExtents.Y = m_frameWorkScene.RegionInfo.RegionSizeY; - m_regionHeight = (uint)WorldExtents.Y; + // Create the world and the first space + world = d.WorldCreate(); + space = d.HashSpaceCreate(IntPtr.Zero); - lock (OdeLock) - { - // Create the world and the first space - try - { - world = d.WorldCreate(); - TopSpace = d.HashSpaceCreate(IntPtr.Zero); + contactgroup = d.JointGroupCreate(0); - // now the major subspaces - ActiveSpace = d.HashSpaceCreate(TopSpace); - CharsSpace = d.HashSpaceCreate(TopSpace); - StaticSpace = d.HashSpaceCreate(TopSpace); - GroundSpace = d.HashSpaceCreate(TopSpace); - } - catch - { - // i must RtC#FM - // i did! - } - - d.HashSpaceSetLevels(TopSpace, -5, 12); - d.HashSpaceSetLevels(ActiveSpace, -5, 10); - d.HashSpaceSetLevels(CharsSpace, -4, 3); - d.HashSpaceSetLevels(StaticSpace, -5, 12); - d.HashSpaceSetLevels(GroundSpace, 0, 8); - - // demote to second level - d.SpaceSetSublevel(ActiveSpace, 1); - d.SpaceSetSublevel(CharsSpace, 1); - d.SpaceSetSublevel(StaticSpace, 1); - d.SpaceSetSublevel(GroundSpace, 1); - - d.GeomSetCategoryBits(ActiveSpace, (uint)(CollisionCategories.Space | - CollisionCategories.Geom | - CollisionCategories.Character | - CollisionCategories.Phantom | - CollisionCategories.VolumeDtc - )); - d.GeomSetCollideBits(ActiveSpace, (uint)(CollisionCategories.Space | - CollisionCategories.Geom | - CollisionCategories.Character | - CollisionCategories.Phantom | - CollisionCategories.VolumeDtc - )); - d.GeomSetCategoryBits(CharsSpace, (uint)(CollisionCategories.Space | - CollisionCategories.Geom | - CollisionCategories.Character | - CollisionCategories.Phantom | - CollisionCategories.VolumeDtc - )); - d.GeomSetCollideBits(CharsSpace, 0); - - d.GeomSetCategoryBits(StaticSpace, (uint)(CollisionCategories.Space | - CollisionCategories.Geom | - // CollisionCategories.Land | - // CollisionCategories.Water | - CollisionCategories.Phantom | - CollisionCategories.VolumeDtc - )); - d.GeomSetCollideBits(StaticSpace, 0); - - d.GeomSetCategoryBits(GroundSpace, (uint)(CollisionCategories.Land)); - d.GeomSetCollideBits(GroundSpace, 0); - - contactgroup = d.JointGroupCreate(maxContactsbeforedeath + 1); - //contactgroup - - d.WorldSetAutoDisableFlag(world, false); - } - - - // checkThread(); + d.WorldSetAutoDisableFlag(world, false); + } + // Initialize from configs + private void InitialiseFromConfig(IConfigSource config) + { + InitializeExtraStats(); + m_config = config; // Defaults + avPIDD = 2200.0f; + avPIDP = 900.0f; + avStandupTensor = 550000f; + int contactsPerCollision = 80; - physicsconfig = null; - if (m_config != null) { - physicsconfig = m_config.Configs["ODEPhysicsSettings"]; + IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; if (physicsconfig != null) { - gravityx = physicsconfig.GetFloat("world_gravityx", gravityx); - gravityy = physicsconfig.GetFloat("world_gravityy", gravityy); - gravityz = physicsconfig.GetFloat("world_gravityz", gravityz); + CollectStats = physicsconfig.GetBoolean("collect_stats", false); - metersInSpace = physicsconfig.GetFloat("meters_in_small_space", metersInSpace); + gravityx = physicsconfig.GetFloat("world_gravityx", 0f); + gravityy = physicsconfig.GetFloat("world_gravityy", 0f); + gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f); - // contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", contactsurfacelayer); + float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 54f); + AvatarTerminalVelocity = Util.Clamp(avatarTerminalVelocity, 0, 255f); + if (AvatarTerminalVelocity != avatarTerminalVelocity) + { + m_log.WarnFormat( + "[ODE SCENE]: avatar_terminal_velocity of {0} is invalid. Clamping to {1}", + avatarTerminalVelocity, AvatarTerminalVelocity); + } + + HashspaceLow = physicsconfig.GetInt("world_hashspace_level_low", -5); + HashspaceHigh = physicsconfig.GetInt("world_hashspace_level_high", 12); + + metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f); + + contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f); + + nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f); + nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f); + nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f); + + mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f); + mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f); + mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f); + + nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f); + nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f); + + mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f); + mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f); ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE); + m_physicsiterations = physicsconfig.GetInt("world_solver_iterations", 10); - avDensity = physicsconfig.GetFloat("av_density", avDensity); - avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", avMovementDivisorWalk); - avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", avMovementDivisorRun); + avDensity = physicsconfig.GetFloat("av_density", 80f); +// avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f); + avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); + avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); + avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); + avplanted = physicsconfig.GetBoolean("av_planted", false); + av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false); - contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", contactsPerCollision); + IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); - geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", geomDefaultDensity); - bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", bodyFramesAutoDisable); + contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); + + geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5); + geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); + + geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f); + bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20); + + bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f); + bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f); + + forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing); + meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true); + meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f); + MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); + m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); + + avPIDD = physicsconfig.GetFloat("av_pid_derivative", 2200.0f); + avPIDP = physicsconfig.GetFloat("av_pid_proportional", 900.0f); + avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor", 550000f); physics_logging = physicsconfig.GetBoolean("physics_logging", false); physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0); physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false); - minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", minimumGroundFlightOffset); - maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", maximumMassObject); - - avDensity *= 3f / 80f; // scale other engines density option to this +// m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false); + minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f); + maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f); } } - float heartbeat = 1/m_frameWorkScene.FrameTime; - maximumAngularVelocity = 0.49f * heartbeat *(float)Math.PI; - maxAngVelocitySQ = maximumAngularVelocity * maximumAngularVelocity; - - d.WorldSetCFM(world, comumContactCFM); - d.WorldSetERP(world, comumContactERP); - - d.WorldSetGravity(world, gravityx, gravityy, gravityz); - - d.WorldSetLinearDamping(world, 0.002f); - d.WorldSetAngularDamping(world, 0.002f); - d.WorldSetAngularDampingThreshold(world, 0f); - d.WorldSetLinearDampingThreshold(world, 0f); - d.WorldSetMaxAngularSpeed(world, maximumAngularVelocity); - - d.WorldSetQuickStepNumIterations(world, m_physicsiterations); - - d.WorldSetContactSurfaceLayer(world, contactsurfacelayer); - d.WorldSetContactMaxCorrectingVel(world, 60.0f); - - HalfOdeStep = ODE_STEPSIZE * 0.5f; - odetimestepMS = (int)(1000.0f * ODE_STEPSIZE + 0.5f); - - ContactgeomsArray = Marshal.AllocHGlobal(contactsPerCollision * d.ContactGeom.unmanagedSizeOf); - GlobalContactsArray = Marshal.AllocHGlobal((maxContactsbeforedeath + 100) * d.Contact.unmanagedSizeOf); - - SharedTmpcontact.geom.g1 = IntPtr.Zero; - SharedTmpcontact.geom.g2 = IntPtr.Zero; - - SharedTmpcontact.geom.side1 = -1; - SharedTmpcontact.geom.side2 = -1; - - SharedTmpcontact.surface.mode = comumContactFlags; - SharedTmpcontact.surface.mu = 0; - SharedTmpcontact.surface.bounce = 0; - SharedTmpcontact.surface.soft_cfm = comumContactCFM; - SharedTmpcontact.surface.soft_erp = comumContactERP; - SharedTmpcontact.surface.slip1 = comumContactSLIP; - SharedTmpcontact.surface.slip2 = comumContactSLIP; - - m_materialContactsData[(int)Material.Stone].mu = 0.8f; - m_materialContactsData[(int)Material.Stone].bounce = 0.4f; - - m_materialContactsData[(int)Material.Metal].mu = 0.3f; - m_materialContactsData[(int)Material.Metal].bounce = 0.4f; - - m_materialContactsData[(int)Material.Glass].mu = 0.2f; - m_materialContactsData[(int)Material.Glass].bounce = 0.7f; - - m_materialContactsData[(int)Material.Wood].mu = 0.6f; - m_materialContactsData[(int)Material.Wood].bounce = 0.5f; - - m_materialContactsData[(int)Material.Flesh].mu = 0.9f; - m_materialContactsData[(int)Material.Flesh].bounce = 0.3f; - - m_materialContactsData[(int)Material.Plastic].mu = 0.4f; - m_materialContactsData[(int)Material.Plastic].bounce = 0.7f; - - m_materialContactsData[(int)Material.Rubber].mu = 0.9f; - m_materialContactsData[(int)Material.Rubber].bounce = 0.95f; - - m_materialContactsData[(int)Material.light].mu = 0.0f; - m_materialContactsData[(int)Material.light].bounce = 0.0f; - + contacts = new d.ContactGeom[contactsPerCollision]; spacesPerMeterX = 1.0f / metersInSpace; - spacesPerMeterY = spacesPerMeterX; + spacesPerMeterY = 1.0f / metersInSpace; + spaceGridMaxX = (int)(WorldExtents.X * spacesPerMeterX); spaceGridMaxY = (int)(WorldExtents.Y * spacesPerMeterY); + // note: limit number of spaces if (spaceGridMaxX > 24) { spaceGridMaxX = 24; - spacesPerMeterX = spaceGridMaxX / WorldExtents.X; + spacesPerMeterX = spaceGridMaxX / WorldExtents.X; } - if (spaceGridMaxY > 24) { spaceGridMaxY = 24; spacesPerMeterY = spaceGridMaxY / WorldExtents.Y; } - staticPrimspace = new IntPtr[spaceGridMaxX, spaceGridMaxY]; + staticPrimspace = new IntPtr[spaceGridMaxX, spaceGridMaxY]; - // create all spaces now - int i, j; - IntPtr newspace; - - for (i = 0; i < spaceGridMaxX; i++) - for (j = 0; j < spaceGridMaxY; j++) - { - newspace = d.HashSpaceCreate(StaticSpace); - d.GeomSetCategoryBits(newspace, (int)CollisionCategories.Space); - waitForSpaceUnlock(newspace); - d.SpaceSetSublevel(newspace, 2); - d.HashSpaceSetLevels(newspace, -2, 8); - d.GeomSetCategoryBits(newspace, (uint)(CollisionCategories.Space | - CollisionCategories.Geom | - CollisionCategories.Land | - CollisionCategories.Water | - CollisionCategories.Phantom | - CollisionCategories.VolumeDtc - )); - d.GeomSetCollideBits(newspace, 0); - - staticPrimspace[i, j] = newspace; - } - - // let this now be index limit + // make this index limits spaceGridMaxX--; spaceGridMaxY--; - // create 4 off world spaces (x<0,x>max,y<0,y>max) - staticPrimspaceOffRegion = new IntPtr[4]; + // Centeral contact friction and bounce + // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why + // an avatar falls through in Z but not in X or Y when walking on a prim. + contact.surface.mode |= d.ContactFlags.SoftERP; + contact.surface.mu = nmAvatarObjectContactFriction; + contact.surface.bounce = nmAvatarObjectContactBounce; + contact.surface.soft_cfm = 0.010f; + contact.surface.soft_erp = 0.010f; - for (i = 0; i < 4; i++) + // Terrain contact friction and Bounce + // This is the *non* moving version. Use this when an avatar + // isn't moving to keep it in place better + TerrainContact.surface.mode |= d.ContactFlags.SoftERP; + TerrainContact.surface.mu = nmTerrainContactFriction; + TerrainContact.surface.bounce = nmTerrainContactBounce; + TerrainContact.surface.soft_erp = nmTerrainContactERP; + + WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM); + WaterContact.surface.mu = 0f; // No friction + WaterContact.surface.bounce = 0.0f; // No bounce + WaterContact.surface.soft_cfm = 0.010f; + WaterContact.surface.soft_erp = 0.010f; + + // Prim contact friction and bounce + // THis is the *non* moving version of friction and bounce + // Use this when an avatar comes in contact with a prim + // and is moving + AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction; + AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce; + + // Terrain contact friction bounce and various error correcting calculations + // Use this when an avatar is in contact with the terrain and moving. + AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP; + AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction; + AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce; + AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP; + + /* + + Stone = 0, + /// + Metal = 1, + /// + Glass = 2, + /// + Wood = 3, + /// + Flesh = 4, + /// + Plastic = 5, + /// + Rubber = 6 + */ + + m_materialContacts = new d.Contact[7,2]; + + m_materialContacts[(int)Material.Stone, 0] = new d.Contact(); + m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Stone, 1] = new d.Contact(); + m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Metal, 0] = new d.Contact(); + m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Metal, 1] = new d.Contact(); + m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Glass, 0] = new d.Contact(); + m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f; + m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f; + m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f; + + /* + private float nmAvatarObjectContactFriction = 250f; + private float nmAvatarObjectContactBounce = 0.1f; + + private float mAvatarObjectContactFriction = 75f; + private float mAvatarObjectContactBounce = 0.1f; + */ + m_materialContacts[(int)Material.Glass, 1] = new d.Contact(); + m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f; + m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f; + m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Wood, 0] = new d.Contact(); + m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Wood, 1] = new d.Contact(); + m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Flesh, 0] = new d.Contact(); + m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Flesh, 1] = new d.Contact(); + m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Plastic, 0] = new d.Contact(); + m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Plastic, 1] = new d.Contact(); + m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Rubber, 0] = new d.Contact(); + m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Rubber, 1] = new d.Contact(); + m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f; + + d.HashSpaceSetLevels(space, HashspaceLow, HashspaceHigh); + + // Set the gravity,, don't disable things automatically (we set it explicitly on some things) + + d.WorldSetGravity(world, gravityx, gravityy, gravityz); + d.WorldSetContactSurfaceLayer(world, contactsurfacelayer); + + d.WorldSetLinearDamping(world, 256f); + d.WorldSetAngularDamping(world, 256f); + d.WorldSetAngularDampingThreshold(world, 256f); + d.WorldSetLinearDampingThreshold(world, 256f); + d.WorldSetMaxAngularSpeed(world, 256f); + + d.WorldSetQuickStepNumIterations(world, m_physicsiterations); + //d.WorldSetContactMaxCorrectingVel(world, 1000.0f); + + for (int i = 0; i < staticPrimspace.GetLength(0); i++) { - newspace = d.HashSpaceCreate(StaticSpace); - d.GeomSetCategoryBits(newspace, (int)CollisionCategories.Space); - waitForSpaceUnlock(newspace); - d.SpaceSetSublevel(newspace, 2); - d.HashSpaceSetLevels(newspace, -2, 8); - d.GeomSetCategoryBits(newspace, (uint)(CollisionCategories.Space | - CollisionCategories.Geom | - CollisionCategories.Land | - CollisionCategories.Water | - CollisionCategories.Phantom | - CollisionCategories.VolumeDtc - )); - d.GeomSetCollideBits(newspace, 0); - - staticPrimspaceOffRegion[i] = newspace; + for (int j = 0; j < staticPrimspace.GetLength(1); j++) + { + staticPrimspace[i, j] = IntPtr.Zero; + } } - m_lastframe = DateTime.UtcNow; - m_lastMeshExpire = m_lastframe; - } - - internal void waitForSpaceUnlock(IntPtr space) - { - //if (space != IntPtr.Zero) - //while (d.SpaceLockQuery(space)) { } // Wait and do nothing + _worldInitialized = true; } #region Collision Detection - // sets a global contact for a joint for contactgeom , and base contact description) - private IntPtr CreateContacJoint(ref d.ContactGeom contactGeom,bool smooth) + /// + /// Collides two geometries. + /// + /// + /// + /// /param> + /// + /// + /// + private int CollideGeoms( + IntPtr geom1, IntPtr geom2, int maxContacts, d.ContactGeom[] contactsArray, int contactGeomSize) { - if (m_global_contactcount >= maxContactsbeforedeath) - return IntPtr.Zero; + int count; - m_global_contactcount++; - if(smooth) - SharedTmpcontact.geom.depth = contactGeom.depth * 0.05f; - else - SharedTmpcontact.geom.depth = contactGeom.depth; - SharedTmpcontact.geom.pos = contactGeom.pos; - SharedTmpcontact.geom.normal = contactGeom.normal; + lock (OdeScene.UniversalColliderSyncObject) + { + // We do this inside the lock so that we don't count any delay in acquiring it + if (CollectStats) + m_nativeCollisionStartTick = Util.EnvironmentTickCount(); - IntPtr contact = new IntPtr(GlobalContactsArray.ToInt64() + (Int64)(m_global_contactcount * d.Contact.unmanagedSizeOf)); - Marshal.StructureToPtr(SharedTmpcontact, contact, true); - return d.JointCreateContactPtr(world, contactgroup, contact); + count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize); + } + + // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably + // negligable + if (CollectStats) + m_stats[ODENativeGeomCollisionFrameMsStatName] + += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); + + return count; } - private bool GetCurContactGeom(int index, ref d.ContactGeom newcontactgeom) + /// + /// Collide two spaces or a space and a geometry. + /// + /// + /// /param> + /// + private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data) { - if (ContactgeomsArray == IntPtr.Zero || index >= contactsPerCollision) - return false; + if (CollectStats) + { + m_inCollisionTiming = true; + m_nativeCollisionStartTick = Util.EnvironmentTickCount(); + } - IntPtr contactptr = new IntPtr(ContactgeomsArray.ToInt64() + (Int64)(index * d.ContactGeom.unmanagedSizeOf)); - newcontactgeom = (d.ContactGeom)Marshal.PtrToStructure(contactptr, typeof(d.ContactGeom)); - return true; + d.SpaceCollide2(space1, space2, data, nearCallback); + + if (CollectStats && m_inCollisionTiming) + { + m_stats[ODENativeSpaceCollisionFrameMsStatName] + += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); + m_inCollisionTiming = false; + } } /// @@ -674,50 +929,70 @@ namespace OpenSim.Region.PhysicsModule.ubOde /// The space that contains the geoms. Remember, spaces are also geoms /// a geometry or space /// another geometry or space - /// - private void near(IntPtr space, IntPtr g1, IntPtr g2) { - // no lock here! It's invoked from within Simulate(), which is thread-locked + if (CollectStats && m_inCollisionTiming) + { + m_stats[ODENativeSpaceCollisionFrameMsStatName] + += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); + m_inCollisionTiming = false; + } - if (m_global_contactcount >= maxContactsbeforedeath) - return; +// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space); + // no lock here! It's invoked from within Simulate(), which is thread-locked // Test if we're colliding a geom with a space. // If so we have to drill down into the space recursively - if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) - return; - if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) { + if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) + return; + + // Separating static prim geometry spaces. // We'll be calling near recursivly if one // of them is a space to find all of the // contact points in the space try { - d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); + CollideSpaces(g1, g2, IntPtr.Zero); } catch (AccessViolationException) { - m_log.Warn("[PHYSICS]: Unable to collide test a space"); + m_log.Error("[ODE SCENE]: Unable to collide test a space"); return; } - //here one should check collisions of geoms inside a space - // but on each space we only should have geoms that not colide amoung each other - // so we don't dig inside spaces + //Colliding a space or a geom with a space or a geom. so drill down + + //Collide all geoms in each space.. + //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); + //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback); return; } - // get geom bodies to check if we already a joint contact - // guess this shouldn't happen now + if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) + return; + IntPtr b1 = d.GeomGetBody(g1); IntPtr b2 = d.GeomGetBody(g2); // d.GeomClassID id = d.GeomGetClass(g1); + String name1 = null; + String name2 = null; + + if (!geom_name_map.TryGetValue(g1, out name1)) + { + name1 = "null"; + } + if (!geom_name_map.TryGetValue(g2, out name2)) + { + name2 = "null"; + } + // Figure out how many contact points we have int count = 0; + try { // Colliding Geom To Geom @@ -728,329 +1003,444 @@ namespace OpenSim.Region.PhysicsModule.ubOde if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) return; - /* - // debug - PhysicsActor dp2; - if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass) - { - d.AABB aabb; - d.GeomGetAABB(g2, out aabb); - float x = aabb.MaxX - aabb.MinX; - float y = aabb.MaxY - aabb.MinY; - float z = aabb.MaxZ - aabb.MinZ; - if (x > 60.0f || y > 60.0f || z > 60.0f) - { - if (!actor_name_map.TryGetValue(g2, out dp2)) - m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2"); - else - m_log.WarnFormat("[PHYSICS]: land versus large prim geo {0},size {1}, AABBsize <{2},{3},{4}>, at {5} ori {6},({7})", - dp2.Name, dp2.Size, x, y, z, - dp2.Position.ToString(), - dp2.Orientation.ToString(), - dp2.Orientation.Length()); - return; - } - } - // - */ + count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.unmanagedSizeOf); - if (d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc || - d.GeomGetCategoryBits(g2) == (uint)CollisionCategories.VolumeDtc) - { - int cflags; - unchecked - { - cflags = (int)(1 | d.CONTACTS_UNIMPORTANT); - } - count = d.CollidePtr(g1, g2, cflags, ContactgeomsArray, d.ContactGeom.unmanagedSizeOf); - } - else - count = d.CollidePtr(g1, g2, (contactsPerCollision & 0xffff), ContactgeomsArray, d.ContactGeom.unmanagedSizeOf); + // All code after this is only relevant if we have any collisions + if (count <= 0) + return; + + if (count > 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.drelease(world); + m_log.Error( + "[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.ErrorFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message); return; } - // contacts done - if (count == 0) - return; - - // try get physical actors PhysicsActor p1; PhysicsActor p2; - + + p1ExpectedPoints = 0; + p2ExpectedPoints = 0; + if (!actor_name_map.TryGetValue(g1, out p1)) { - m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 1"); - return; + p1 = PANull; } if (!actor_name_map.TryGetValue(g2, out p2)) { - m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2"); - return; + p2 = PANull; } - - // get first contact - d.ContactGeom curContact = new d.ContactGeom(); - - if (!GetCurContactGeom(0, ref curContact)) - return; - ContactPoint maxDepthContact = new ContactPoint(); + if (p1.CollisionScore + count >= float.MaxValue) + p1.CollisionScore = 0; + p1.CollisionScore += count; - // do volume detection case - if ((p1.IsVolumeDtc || p2.IsVolumeDtc)) + if (p2.CollisionScore + count >= float.MaxValue) + p2.CollisionScore = 0; + p2.CollisionScore += count; + + for (int i = 0; i < count; i++) { - maxDepthContact = new ContactPoint( - new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), - new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), - curContact.depth, false + d.ContactGeom curContact = contacts[i]; + + if (curContact.depth > maxDepthContact.PenetrationDepth) + { + maxDepthContact = new ContactPoint( + new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), + new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), + curContact.depth ); - - collision_accounting_events(p1, p2, maxDepthContact); - return; - } - - // big messy collision analises - - float mu = 0; - float bounce = 0; -// bool IgnoreNegSides = false; - - ContactData contactdata1 = new ContactData(0, 0, false); - ContactData contactdata2 = new ContactData(0, 0, false); - - bool dop1ava = false; - bool dop2ava = false; - bool ignore = false; - bool smoothMesh = false; - - switch (p1.PhysicsActorType) - { - case (int)ActorTypes.Agent: - { - dop1ava = true; - switch (p2.PhysicsActorType) - { - case (int)ActorTypes.Agent: - case (int)ActorTypes.Prim: - break; - - default: - ignore = true; // avatar to terrain and water ignored - break; - } - break; - } - - case (int)ActorTypes.Prim: - { - switch (p2.PhysicsActorType) - { - case (int)ActorTypes.Agent: - dop2ava = true; - break; - - case (int)ActorTypes.Prim: - Vector3 relV = p1.rootVelocity - p2.rootVelocity; - float relVlenSQ = relV.LengthSquared(); - if (relVlenSQ > 0.0001f) - { - p1.CollidingObj = true; - p2.CollidingObj = true; - } - p1.getContactData(ref contactdata1); - p2.getContactData(ref contactdata2); - bounce = contactdata1.bounce * contactdata2.bounce; - mu = (float)Math.Sqrt(contactdata1.mu * contactdata2.mu); - - if (relVlenSQ > 0.01f) - mu *= frictionMovementMult; - - if(d.GeomGetClass(g2) == d.GeomClassID.TriMeshClass && - d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass) - smoothMesh = true; - break; - - case (int)ActorTypes.Ground: - p1.getContactData(ref contactdata1); - bounce = contactdata1.bounce * TerrainBounce; - mu = (float)Math.Sqrt(contactdata1.mu * TerrainFriction); - - Vector3 v1 = p1.rootVelocity; - if (Math.Abs(v1.X) > 0.1f || Math.Abs(v1.Y) > 0.1f) - mu *= frictionMovementMult; - p1.CollidingGround = true; - - if(d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass) - smoothMesh = true; - break; - - case (int)ActorTypes.Water: - default: - ignore = true; - break; - } - } - break; - - case (int)ActorTypes.Ground: - if (p2.PhysicsActorType == (int)ActorTypes.Prim) - { - p2.CollidingGround = true; - p2.getContactData(ref contactdata2); - bounce = contactdata2.bounce * TerrainBounce; - mu = (float)Math.Sqrt(contactdata2.mu * TerrainFriction); - -// if (curContact.side1 > 0) // should be 2 ? -// IgnoreNegSides = true; - Vector3 v2 = p2.rootVelocity; - if (Math.Abs(v2.X) > 0.1f || Math.Abs(v2.Y) > 0.1f) - mu *= frictionMovementMult; - - if(d.GeomGetClass(g2) == d.GeomClassID.TriMeshClass) - smoothMesh = true; - } - else - ignore = true; - break; - - case (int)ActorTypes.Water: - default: - break; - } - - if (ignore) - return; - - IntPtr Joint; - bool FeetCollision = false; - int ncontacts = 0; - - int i = 0; - - maxDepthContact = new ContactPoint(); - maxDepthContact.PenetrationDepth = float.MinValue; - ContactPoint minDepthContact = new ContactPoint(); - minDepthContact.PenetrationDepth = float.MaxValue; - - SharedTmpcontact.geom.depth = 0; - SharedTmpcontact.surface.mu = mu; - SharedTmpcontact.surface.bounce = bounce; - - d.ContactGeom altContact = new d.ContactGeom(); - bool useAltcontact = false; - bool noskip = true; - - if(dop1ava || dop2ava) - smoothMesh = false; - - while (true) - { - noskip = true; - useAltcontact = false; - - if (dop1ava) - { - if ((((OdeCharacter)p1).Collide(g1, g2, false, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision))) - { - if (p2.PhysicsActorType == (int)ActorTypes.Agent) - { - p1.CollidingObj = true; - p2.CollidingObj = true; - } - else if (p2.rootVelocity.LengthSquared() > 0.0f) - p2.CollidingObj = true; - } - else - noskip = false; } - else if (dop2ava) + + //m_log.Warn("[CCOUNT]: " + count); + IntPtr joint; + // If we're colliding with terrain, use 'TerrainContact' instead of contact. + // allows us to have different settings + + // We only need to test p2 for 'jump crouch purposes' + if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim) { - if ((((OdeCharacter)p2).Collide(g2, g1, true, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision))) - { - if (p1.PhysicsActorType == (int)ActorTypes.Agent) - { - p1.CollidingObj = true; - p2.CollidingObj = true; - } - else if (p1.rootVelocity.LengthSquared() > 0.0f) - p1.CollidingObj = true; - } + // Testing if the collision is at the feet of the avatar + + //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f)); + if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f)) + p2.IsColliding = true; + } else - noskip = false; - } - - if (noskip) { - if(useAltcontact) - Joint = CreateContacJoint(ref altContact,smoothMesh); - else - Joint = CreateContacJoint(ref curContact,smoothMesh); + p2.IsColliding = true; + } + + //if ((framecount % m_returncollisions) == 0) - if (Joint == IntPtr.Zero) + switch (p1.PhysicsActorType) + { + case (int)ActorTypes.Agent: + p1ExpectedPoints = avatarExpectedContacts; + p2.CollidingObj = true; break; + case (int)ActorTypes.Prim: + if (p1 != null && p1 is OdePrim) + p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts; - d.JointAttach(Joint, b1, b2); + if (p2.Velocity.LengthSquared() > 0.0f) + p2.CollidingObj = true; + break; + case (int)ActorTypes.Unknown: + p2.CollidingGround = true; + break; + default: + p2.CollidingGround = true; + break; + } - ncontacts++; + // we don't want prim or avatar to explode - if (curContact.depth > maxDepthContact.PenetrationDepth) + #region InterPenetration Handling - Unintended physics explosions + + if (curContact.depth >= 0.08f) + { + if (curContact.depth >= 1.00f) { - maxDepthContact.Position.X = curContact.pos.X; - maxDepthContact.Position.Y = curContact.pos.Y; - maxDepthContact.Position.Z = curContact.pos.Z; - maxDepthContact.PenetrationDepth = curContact.depth; - maxDepthContact.CharacterFeet = FeetCollision; - } + //m_log.Info("[P]: " + contact.depth.ToString()); + if ((p2.PhysicsActorType == (int) ActorTypes.Agent && + p1.PhysicsActorType == (int) ActorTypes.Unknown) || + (p1.PhysicsActorType == (int) ActorTypes.Agent && + p2.PhysicsActorType == (int) ActorTypes.Unknown)) + { + if (p2.PhysicsActorType == (int) ActorTypes.Agent) + { + if (p2 is OdeCharacter) + { + OdeCharacter character = (OdeCharacter) p2; - if (curContact.depth < minDepthContact.PenetrationDepth) - { - minDepthContact.PenetrationDepth = curContact.depth; - minDepthContact.SurfaceNormal.X = curContact.normal.X; - minDepthContact.SurfaceNormal.Y = curContact.normal.Y; - minDepthContact.SurfaceNormal.Z = curContact.normal.Z; + //p2.CollidingObj = true; + curContact.depth = 0.00000003f; + p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f); + curContact.pos = + new d.Vector3(curContact.pos.X + (p1.Size.X/2), + curContact.pos.Y + (p1.Size.Y/2), + curContact.pos.Z + (p1.Size.Z/2)); + character.SetPidStatus(true); + } + } + + if (p1.PhysicsActorType == (int) ActorTypes.Agent) + { + if (p1 is OdeCharacter) + { + OdeCharacter character = (OdeCharacter) p1; + + //p2.CollidingObj = true; + curContact.depth = 0.00000003f; + p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f); + curContact.pos = + new d.Vector3(curContact.pos.X + (p1.Size.X/2), + curContact.pos.Y + (p1.Size.Y/2), + curContact.pos.Z + (p1.Size.Z/2)); + character.SetPidStatus(true); + } + } + } } } - if (++i >= count) - break; + #endregion - if (!GetCurContactGeom(i, ref curContact)) - break; - } + // Logic for collision handling + // Note, that if *all* contacts are skipped (VolumeDetect) + // The prim still detects (and forwards) collision events but + // appears to be phantom for the world + Boolean skipThisContact = false; - if (ncontacts > 0) - { - maxDepthContact.SurfaceNormal.X = minDepthContact.SurfaceNormal.X; - maxDepthContact.SurfaceNormal.Y = minDepthContact.SurfaceNormal.Y; - maxDepthContact.SurfaceNormal.Z = minDepthContact.SurfaceNormal.Z; + if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) + skipThisContact = true; // No collision on volume detect prims + + if (av_av_collisions_off) + if ((p1 is OdeCharacter) && (p2 is OdeCharacter)) + skipThisContact = true; + + if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) + skipThisContact = true; // No collision on volume detect prims + + if (!skipThisContact && curContact.depth < 0f) + skipThisContact = true; + + if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType)) + skipThisContact = true; + + const int maxContactsbeforedeath = 4000; + joint = IntPtr.Zero; + + if (!skipThisContact) + { + _perloopContact.Add(curContact); + + if (name1 == "Terrain" || name2 == "Terrain") + { + if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && + (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) + { + p2ExpectedPoints = avatarExpectedContacts; + // Avatar is moving on terrain, use the movement terrain contact + AvatarMovementTerrainContact.geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); + m_global_contactcount++; + } + } + else + { + if (p2.PhysicsActorType == (int)ActorTypes.Agent) + { + p2ExpectedPoints = avatarExpectedContacts; + // Avatar is standing on terrain, use the non moving terrain contact + TerrainContact.geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); + m_global_contactcount++; + } + } + else + { + if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim) + { + // prim prim contact + // int pj294950 = 0; + int movintYN = 0; + int material = (int) Material.Wood; + // prim terrain contact + if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) + { + movintYN = 1; + } + + if (p2 is OdePrim) + { + material = ((OdePrim) p2).m_material; + p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; + } + + // Unnessesary because p1 is defined above + //if (p1 is OdePrim) + // { + // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts; + // } + //m_log.DebugFormat("Material: {0}", material); + + m_materialContacts[material, movintYN].geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); + m_global_contactcount++; + } + } + else + { + int movintYN = 0; + // prim terrain contact + if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) + { + movintYN = 1; + } + + int material = (int)Material.Wood; + + if (p2 is OdePrim) + { + material = ((OdePrim)p2).m_material; + p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; + } + + //m_log.DebugFormat("Material: {0}", material); + m_materialContacts[material, movintYN].geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); + m_global_contactcount++; + } + } + } + } + //if (p2.PhysicsActorType == (int)ActorTypes.Prim) + //{ + //m_log.Debug("[PHYSICS]: prim contacting with ground"); + //} + } + else if (name1 == "Water" || name2 == "Water") + { + /* + if ((p2.PhysicsActorType == (int) ActorTypes.Prim)) + { + } + else + { + } + */ + //WaterContact.surface.soft_cfm = 0.0000f; + //WaterContact.surface.soft_erp = 0.00000f; + if (curContact.depth > 0.1f) + { + curContact.depth *= 52; + //contact.normal = new d.Vector3(0, 0, 1); + //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f); + } + + WaterContact.geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref WaterContact); + m_global_contactcount++; + } + //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth); + } + else + { + if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) + { + p2ExpectedPoints = avatarExpectedContacts; + if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) + { + // Avatar is moving on a prim, use the Movement prim contact + AvatarMovementprimContact.geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); + m_global_contactcount++; + } + } + else + { + // Avatar is standing still on a prim, use the non movement contact + contact.geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref contact); + m_global_contactcount++; + } + } + } + else if (p2.PhysicsActorType == (int)ActorTypes.Prim) + { + //p1.PhysicsActorType + int material = (int)Material.Wood; + + if (p2 is OdePrim) + { + material = ((OdePrim)p2).m_material; + p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; + } + + //m_log.DebugFormat("Material: {0}", material); + m_materialContacts[material, 0].geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]); + m_global_contactcount++; + } + } + } + + if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide! + { + d.JointAttach(joint, b1, b2); + m_global_contactcount++; + } + } collision_accounting_events(p1, p2, maxDepthContact); + + if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle)) + { + // If there are more then 3 contact points, it's likely + // that we've got a pile of objects, so ... + // We don't want to send out hundreds of terse updates over and over again + // so lets throttle them and send them again after it's somewhat sorted out. + p2.ThrottleUpdates = true; + } + //m_log.Debug(count.ToString()); + //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2); } } + private bool checkDupe(d.ContactGeom contactGeom, int atype) + { + if (!m_filterCollisions) + return false; + + bool result = false; + + ActorTypes at = (ActorTypes)atype; + + 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 (((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))) + { + if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) + { + result = true; + break; + } + } + } + else if (at == ActorTypes.Prim) + { + 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))) + { + 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("[Collision]: 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)); + } + } + } + + return result; + } + private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) { - uint obj2LocalID = 0; - - // update actors collision score - if (p1.CollisionScore < float.MaxValue) - p1.CollisionScore += 1.0f; - if (p2.CollisionScore < float.MaxValue) - p2.CollisionScore += 1.0f; - + // obj1LocalID = 0; + //returncollisions = false; + obj2LocalID = 0; + //ctype = 0; + //cStartStop = 0; +// if (!p2.SubscribedEvents() && !p1.SubscribedEvents()) +// return; bool p1events = p1.SubscribedEvents(); bool p2events = p2.SubscribedEvents(); @@ -1064,170 +1454,369 @@ namespace OpenSim.Region.PhysicsModule.ubOde Vector3 vel = Vector3.Zero; if (p2 != null && p2.IsPhysical) - vel = p2.rootVelocity; + vel = p2.Velocity; if (p1 != null && p1.IsPhysical) - vel -= p1.rootVelocity; + vel -= p1.Velocity; contact.RelativeSpeed = Vector3.Dot(vel, contact.SurfaceNormal); - switch ((ActorTypes)p1.PhysicsActorType) + switch ((ActorTypes)p2.PhysicsActorType) { case ActorTypes.Agent: - case ActorTypes.Prim: - { - switch ((ActorTypes)p2.PhysicsActorType) + cc2 = (OdeCharacter)p2; + + // obj1LocalID = cc2.m_localID; + switch ((ActorTypes)p1.PhysicsActorType) { case ActorTypes.Agent: + cc1 = (OdeCharacter)p1; + obj2LocalID = cc1.LocalID; + cc1.AddCollisionEvent(cc2.LocalID, contact); + break; + case ActorTypes.Prim: - if (p2events) + if (p1 is OdePrim) { - AddCollisionEventReporting(p2); - p2.AddCollisionEvent(p1.ParentActor.LocalID, contact); + cp1 = (OdePrim) p1; + obj2LocalID = cp1.LocalID; + cp1.AddCollisionEvent(cc2.LocalID, contact); } - obj2LocalID = p2.ParentActor.LocalID; break; case ActorTypes.Ground: case ActorTypes.Unknown: - default: obj2LocalID = 0; break; } - if (p1events) + + cc2.AddCollisionEvent(obj2LocalID, contact); + break; + + case ActorTypes.Prim: + + if (p2 is OdePrim) { - contact.SurfaceNormal = -contact.SurfaceNormal; - contact.RelativeSpeed = -contact.RelativeSpeed; - AddCollisionEventReporting(p1); - p1.AddCollisionEvent(obj2LocalID, contact); + cp2 = (OdePrim) p2; + + // obj1LocalID = cp2.m_localID; + switch ((ActorTypes) p1.PhysicsActorType) + { + case ActorTypes.Agent: + if (p1 is OdeCharacter) + { + cc1 = (OdeCharacter) p1; + obj2LocalID = cc1.LocalID; + cc1.AddCollisionEvent(cp2.LocalID, contact); + } + break; + case ActorTypes.Prim: + + if (p1 is OdePrim) + { + cp1 = (OdePrim) p1; + obj2LocalID = cp1.LocalID; + cp1.AddCollisionEvent(cp2.LocalID, contact); + } + break; + + case ActorTypes.Ground: + case ActorTypes.Unknown: + obj2LocalID = 0; + break; + } + + cp2.AddCollisionEvent(obj2LocalID, contact); } break; - } - case ActorTypes.Ground: - case ActorTypes.Unknown: - default: - { - if (p2events && !p2.IsVolumeDtc) - { - AddCollisionEventReporting(p2); - p2.AddCollisionEvent(0, contact); - } - break; - } } } - /// /// This is our collision testing routine in ODE /// - /// private void collision_optimized() { - lock (_characters) - { + _perloopContact.Clear(); + + foreach (OdeCharacter chr in _characters) + { + // Reset the collision values to false + // since we don't know if we're colliding yet + 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 { - foreach (OdeCharacter chr in _characters) - { - if (chr == null) - continue; - - chr.IsColliding = false; - // chr.CollidingGround = false; not done here - chr.CollidingObj = false; - - if(chr.Body == IntPtr.Zero || chr.collider == IntPtr.Zero ) - continue; - - // do colisions with static space - d.SpaceCollide2(chr.collider, StaticSpace, IntPtr.Zero, nearCallback); - - // no coll with gnd - } - // chars with chars - d.SpaceCollide(CharsSpace, IntPtr.Zero, nearCallback); - + CollideSpaces(space, chr.Shell, IntPtr.Zero); } catch (AccessViolationException) { - m_log.Warn("[PHYSICS]: Unable to collide Character to static space"); + m_log.ErrorFormat("[ODE SCENE]: Unable to space collide {0}", PhysicsSceneName); } - + + //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) + if (CollectStats) { - foreach (OdePrim aprim in _activeprims) - { - aprim.CollisionScore = 0; - aprim.IsColliding = false; - } + m_tempAvatarCollisionsThisFrame = _perloopContact.Count; + m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame; } - lock (_activegroups) + + List removeprims = null; + foreach (OdePrim chr in _activeprims) { - try + if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled)) { - foreach (OdePrim aprim in _activegroups) + try { - if(!aprim.m_outbounds && d.BodyIsEnabled(aprim.Body) && - aprim.collide_geom != IntPtr.Zero) + lock (chr) { - d.SpaceCollide2(StaticSpace, aprim.collide_geom, IntPtr.Zero, nearCallback); - d.SpaceCollide2(GroundSpace, aprim.collide_geom, IntPtr.Zero, nearCallback); + if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false) + { + CollideSpaces(space, chr.prim_geom, IntPtr.Zero); + } + else + { + if (removeprims == null) + { + removeprims = new List(); + } + removeprims.Add(chr); + m_log.Error( + "[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.Error("[ODE SCENE]: Unable to space collide"); + } } - catch (Exception e) + } + + if (CollectStats) + m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame; + + if (removeprims != null) + { + foreach (OdePrim chr in removeprims) { - m_log.Warn("[PHYSICS]: Unable to collide Active to Static: " + e.Message); + _activeprims.Remove(chr); } } - - // colide active amoung them - try - { - d.SpaceCollide(ActiveSpace, IntPtr.Zero, nearCallback); - } - catch (Exception e) - { - m_log.Warn("[PHYSICS]: Unable to collide in Active: " + e.Message); - } - - // and with chars - try - { - d.SpaceCollide2(CharsSpace,ActiveSpace, IntPtr.Zero, nearCallback); - } - catch (Exception e) - { - m_log.Warn("[PHYSICS]: Unable to collide Active to Character: " + e.Message); - } } #endregion + + // Recovered for use by fly height. Kitto Flora + internal float GetTerrainHeightAtXY(float x, float y) + { + IntPtr heightFieldGeom = IntPtr.Zero; + int offsetX = 0; + int offsetY = 0; + + if(RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom)) + { + if (heightFieldGeom != IntPtr.Zero) + { + if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom)) + { + + int index; + + + if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y || + (int)x < 0.001f || (int)y < 0.001f) + return 0; + + x = x - offsetX + 1f; + y = y - offsetY + 1f; + + // map is rotated + index = (int)x * ((int)m_regionHeight + 3) + (int)y; + + if (index < TerrainHeightFieldHeights[heightFieldGeom].Length) + { + //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]); + return (float)TerrainHeightFieldHeights[heightFieldGeom][index]; + } + + else + return 0f; + } + else + { + return 0f; + } + + } + else + { + return 0f; + } + + } + else + { + return 0f; + } + } +// End recovered. Kitto Flora + /// /// Add actor to the list that should receive collision events in the simulate loop. /// /// - public void AddCollisionEventReporting(PhysicsActor obj) + internal void AddCollisionEventReporting(PhysicsActor obj) { - if (!_collisionEventPrim.Contains(obj)) - _collisionEventPrim.Add(obj); +// m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID); + + lock (m_collisionEventActorsChanges) + m_collisionEventActorsChanges[obj.LocalID] = obj; } /// /// Remove actor from the list that should receive collision events in the simulate loop. /// /// - public void RemoveCollisionEventReporting(PhysicsActor obj) + internal void RemoveCollisionEventReporting(PhysicsActor obj) { - lock(_collisionEventPrimRemove) +// m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID); + + lock (m_collisionEventActorsChanges) + m_collisionEventActorsChanges[obj.LocalID] = null; + } + + #region Add/Remove Entities + + public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) + { + d.AllocateODEDataForThread(0); + + OdeCharacter newAv + = new OdeCharacter( + avName, this, position, velocity, size, avPIDD, avPIDP, + avCapRadius, avStandupTensor, avDensity, + avMovementDivisorWalk, avMovementDivisorRun); + + newAv.Flying = isFlying; + newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; + newAv.m_avatarplanted = avplanted; + + return newAv; + } + + public override void RemoveAvatar(PhysicsActor actor) + { +// m_log.DebugFormat( +// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}", +// actor.Name, actor.LocalID, Name); + + lock (OdeLock) { - if (_collisionEventPrim.Contains(obj) && !_collisionEventPrimRemove.Contains(obj)) - _collisionEventPrimRemove.Add(obj); + d.AllocateODEDataForThread(0); + + ((OdeCharacter) actor).Destroy(); } } + internal void AddCharacter(OdeCharacter chr) + { + chr.m_avatarplanted = avplanted; + if (!_characters.Contains(chr)) + { + _characters.Add(chr); + +// m_log.DebugFormat( +// "[ODE SCENE]: Adding physics character {0} {1} to physics scene {2}. Count now {3}", +// chr.Name, chr.LocalID, Name, _characters.Count); + + if (chr.bad) + 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) + { + if (_characters.Contains(chr)) + { + _characters.Remove(chr); + +// m_log.DebugFormat( +// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}. Count now {3}", +// chr.Name, chr.LocalID, Name, _characters.Count); + } + 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, + PrimitiveBaseShape pbs, bool isphysical, uint localID) + { + Vector3 pos = position; + Vector3 siz = size; + Quaternion rot = rotation; + + + OdePrim newPrim; + lock (OdeLock) + { + d.AllocateODEDataForThread(0); + newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical); + + lock (_prims) + _prims.Add(newPrim); + } + newPrim.LocalID = localID; + return newPrim; + } + + /// + /// Make this prim subject to physics. + /// + /// + internal void ActivatePrim(OdePrim prim) + { + // adds active prim.. (ones that should be iterated over in collisions_optimized + 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, + Vector3 size, Quaternion rotation, bool isPhysical, uint localid) + { +// m_log.DebugFormat("[ODE SCENE]: Adding physics prim {0} {1} to physics scene {2}", primName, localid, Name); + + return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid); + } + public override float TimeDilation { get { return m_timeDilation; } @@ -1235,133 +1824,362 @@ namespace OpenSim.Region.PhysicsModule.ubOde public override bool SupportsNINJAJoints { - get { return false; } + get { return m_NINJA_physics_joints_enabled; } } - #region Add/Remove Entities - - public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) + // internal utility function: must be called within a lock (OdeLock) + private void InternalAddActiveJoint(PhysicsJoint joint) { - return null; + activeJoints.Add(joint); + SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint); } - public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, float feetOffset, bool isFlying) + // internal utility function: must be called within a lock (OdeLock) + private void InternalAddPendingJoint(OdePhysicsJoint joint) { - OdeCharacter newAv = new OdeCharacter(localID, avName, this, position, - size, feetOffset, avDensity, avMovementDivisorWalk, avMovementDivisorRun); - newAv.Flying = isFlying; - newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; - - return newAv; + pendingJoints.Add(joint); + SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint); } - public void AddCharacter(OdeCharacter chr) + // internal utility function: must be called within a lock (OdeLock) + private void InternalRemovePendingJoint(PhysicsJoint joint) { - lock (_characters) + pendingJoints.Remove(joint); + SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene); + } + + // internal utility function: must be called within a lock (OdeLock) + private void InternalRemoveActiveJoint(PhysicsJoint joint) + { + activeJoints.Remove(joint); + SOPName_to_activeJoint.Remove(joint.ObjectNameInScene); + } + + public override void DumpJointInfo() + { + string hdr = "[NINJA] JOINTINFO: "; + foreach (PhysicsJoint j in pendingJoints) { - if (!_characters.Contains(chr)) + m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); + } + m_log.Debug(hdr + pendingJoints.Count + " total pending joints"); + foreach (string jointName in SOPName_to_pendingJoint.Keys) + { + m_log.Debug(hdr + " pending joints dict contains Name: " + jointName); + } + m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries"); + foreach (PhysicsJoint j in activeJoints) + { + m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); + } + m_log.Debug(hdr + activeJoints.Count + " total active joints"); + foreach (string jointName in SOPName_to_activeJoint.Keys) + { + m_log.Debug(hdr + " active joints dict contains Name: " + jointName); + } + m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries"); + + m_log.Debug(hdr + " Per-body joint connectivity information follows."); + m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints."); + foreach (string actorName in joints_connecting_actor.Keys) + { + m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it"); + foreach (PhysicsJoint j in joints_connecting_actor[actorName]) { - _characters.Add(chr); - if (chr.bad) - m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid); + m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); + } + m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor"); + } + } + + public override void RequestJointDeletion(string ObjectNameInScene) + { + lock (externalJointRequestsLock) + { + if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously + { + requestedJointsToBeDeleted.Add(ObjectNameInScene); } } } - public void RemoveCharacter(OdeCharacter chr) + private void DeleteRequestedJoints() { - lock (_characters) + List myRequestedJointsToBeDeleted; + lock (externalJointRequestsLock) { - if (_characters.Contains(chr)) + // make a local copy of the shared list for processing (threading issues) + myRequestedJointsToBeDeleted = new List(requestedJointsToBeDeleted); + } + + foreach (string jointName in myRequestedJointsToBeDeleted) + { + lock (OdeLock) { - _characters.Remove(chr); + //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName); + if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName)) + { + OdePhysicsJoint joint = null; + if (SOPName_to_activeJoint.ContainsKey(jointName)) + { + joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint; + InternalRemoveActiveJoint(joint); + } + else if (SOPName_to_pendingJoint.ContainsKey(jointName)) + { + joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint; + InternalRemovePendingJoint(joint); + } + + if (joint != null) + { + //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames); + for (int iBodyName = 0; iBodyName < 2; iBodyName++) + { + string bodyName = joint.BodyNames[iBodyName]; + if (bodyName != "NULL") + { + joints_connecting_actor[bodyName].Remove(joint); + if (joints_connecting_actor[bodyName].Count == 0) + { + joints_connecting_actor.Remove(bodyName); + } + } + } + + DoJointDeactivated(joint); + if (joint.jointID != IntPtr.Zero) + { + d.JointDestroy(joint.jointID); + joint.jointID = IntPtr.Zero; + //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName); + } + else + { + //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName); + } + } + else + { + // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName); + } + } + else + { + // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName); + } + } + } + + // remove processed joints from the shared list + lock (externalJointRequestsLock) + { + foreach (string jointName in myRequestedJointsToBeDeleted) + { + requestedJointsToBeDeleted.Remove(jointName); } } } - public void BadCharacter(OdeCharacter chr) + // for pending joints we don't know if their associated bodies exist yet or not. + // the joint is actually created during processing of the taints + private void CreateRequestedJoints() { - lock (_badCharacter) + List myRequestedJointsToBeCreated; + lock (externalJointRequestsLock) { - if (!_badCharacter.Contains(chr)) - _badCharacter.Add(chr); + // make a local copy of the shared list for processing (threading issues) + myRequestedJointsToBeCreated = new List(requestedJointsToBeCreated); + } + + foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) + { + lock (OdeLock) + { + if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null) + { + DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); + continue; + } + if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null) + { + DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); + continue; + } + + InternalAddPendingJoint(joint as OdePhysicsJoint); + + if (joint.BodyNames.Count >= 2) + { + for (int iBodyName = 0; iBodyName < 2; iBodyName++) + { + string bodyName = joint.BodyNames[iBodyName]; + if (bodyName != "NULL") + { + if (!joints_connecting_actor.ContainsKey(bodyName)) + { + joints_connecting_actor.Add(bodyName, new List()); + } + joints_connecting_actor[bodyName].Add(joint); + } + } + } + } + } + + // remove processed joints from shared list + lock (externalJointRequestsLock) + { + foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) + { + requestedJointsToBeCreated.Remove(joint); + } } } - public override void RemoveAvatar(PhysicsActor actor) + /// + /// Add a request for joint creation. + /// + /// + /// this joint will just be added to a waiting list that is NOT processed during the main + /// Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public override PhysicsJoint RequestJointCreation( + string objectNameInScene, PhysicsJointType jointType, Vector3 position, + Quaternion rotation, string parms, List bodyNames, string trackedBodyName, Quaternion localRotation) { - //m_log.Debug("[PHYSICS]:ODELOCK"); + OdePhysicsJoint joint = new OdePhysicsJoint(); + joint.ObjectNameInScene = objectNameInScene; + joint.Type = jointType; + joint.Position = position; + joint.Rotation = rotation; + joint.RawParams = parms; + joint.BodyNames = new List(bodyNames); + joint.TrackedBodyName = trackedBodyName; + joint.LocalRotation = localRotation; + joint.jointID = IntPtr.Zero; + joint.ErrorMessageCount = 0; + + lock (externalJointRequestsLock) + { + if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice + { + requestedJointsToBeCreated.Add(joint); + } + } + + return joint; + } + + private void RemoveAllJointsConnectedToActor(PhysicsActor actor) + { + //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]) + { + jointsToRemove.Add(j); + } + foreach (PhysicsJoint j in jointsToRemove) + { + //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene); + RequestJointDeletion(j.ObjectNameInScene); + //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene); + j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing) + } + } + } + + public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor) + { + //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start"); lock (OdeLock) { - d.AllocateODEDataForThread(0); - ((OdeCharacter) actor).Destroy(); + //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock"); + RemoveAllJointsConnectedToActor(actor); } } - - public void addActivePrim(OdePrim activatePrim) + // normally called from within OnJointMoved, which is called from within a lock (OdeLock) + public override Vector3 GetJointAnchor(PhysicsJoint joint) { - // adds active prim.. - lock (_activeprims) + Debug.Assert(joint.IsInPhysicsEngine); + d.Vector3 pos = new d.Vector3(); + + if (!(joint is OdePhysicsJoint)) { - if (!_activeprims.Contains(activatePrim)) - _activeprims.Add(activatePrim); + DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); } - } - - public void addActiveGroups(OdePrim activatePrim) - { - lock (_activegroups) + else { - if (!_activegroups.Contains(activatePrim)) - _activegroups.Add(activatePrim); + OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; + switch (odeJoint.Type) + { + case PhysicsJointType.Ball: + d.JointGetBallAnchor(odeJoint.jointID, out pos); + break; + case PhysicsJointType.Hinge: + d.JointGetHingeAnchor(odeJoint.jointID, out pos); + break; + } } + return new Vector3(pos.X, pos.Y, pos.Z); } - private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, - PrimitiveBaseShape pbs, bool isphysical, bool isPhantom, byte shapeType, uint localID) + /// + /// Get joint axis. + /// + /// + /// normally called from within OnJointMoved, which is called from within a lock (OdeLock) + /// WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function + /// appears to be unreliable. Fortunately we can compute the joint axis ourselves by + /// keeping track of the joint's original orientation relative to one of the involved bodies. + /// + /// + /// + public override Vector3 GetJointAxis(PhysicsJoint joint) { - OdePrim newPrim; - lock (OdeLock) + Debug.Assert(joint.IsInPhysicsEngine); + d.Vector3 axis = new d.Vector3(); + + if (!(joint is OdePhysicsJoint)) { - - newPrim = new OdePrim(name, this, position, size, rotation, pbs, isphysical, isPhantom, shapeType, localID); + DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); } - return newPrim; - } - - public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, - Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, uint localid) - { - return AddPrim(primName, position, size, rotation, pbs, isPhysical, isPhantom, 0 , localid); - } - - - public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, - Vector3 size, Quaternion rotation, bool isPhysical, uint localid) - { - return AddPrim(primName, position, size, rotation, pbs, isPhysical,false, 0, localid); - } - - public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, - Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapeType, uint localid) - { - return AddPrim(primName, position, size, rotation, pbs, isPhysical,isPhantom, shapeType, localid); - } - - public void remActivePrim(OdePrim deactivatePrim) - { - lock (_activeprims) + else { - _activeprims.Remove(deactivatePrim); + OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; + switch (odeJoint.Type) + { + case PhysicsJointType.Ball: + DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene); + break; + case PhysicsJointType.Hinge: + d.JointGetHingeAxis(odeJoint.jointID, out axis); + break; + } } + return new Vector3(axis.X, axis.Y, axis.Z); } - public void remActiveGroup(OdePrim deactivatePrim) + + /// + /// Stop this prim being subject to physics + /// + /// + internal void DeactivatePrim(OdePrim prim) { - lock (_activegroups) - { - _activegroups.Remove(deactivatePrim); - } + _activeprims.Remove(prim); } public override void RemovePrim(PhysicsActor prim) @@ -1370,200 +2188,434 @@ namespace OpenSim.Region.PhysicsModule.ubOde // removed in the next physics simulate pass. if (prim is OdePrim) { -// lock (OdeLock) + lock (OdeLock) { - - OdePrim p = (OdePrim)prim; + OdePrim p = (OdePrim) prim; + p.setPrimForRemoval(); + AddPhysicsActorTaint(prim); } } } - public void RemovePrimThreadLocked(OdePrim prim) + /// + /// This is called from within simulate but outside the locked portion + /// We need to do our own locking here + /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in + /// Simulate() -- justincc). + /// + /// Essentially, we need to remove the prim from our space segment, whatever segment it's in. + /// + /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory + /// that the space was using. + /// + /// + internal void RemovePrimThreadLocked(OdePrim prim) { - //Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName); +// m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID); + lock (prim) { -// RemoveCollisionEventReporting(prim); - lock (_prims) - _prims.Remove(prim.LocalID); - } + RemoveCollisionEventReporting(prim); - } + if (prim.prim_geom != IntPtr.Zero) + { + prim.ResetTaints(); - public void addToPrims(OdePrim prim) - { - lock (_prims) - _prims[prim.LocalID] = prim; - } + if (prim.IsPhysical) + { + prim.disableBody(); + if (prim.childPrim) + { + prim.childPrim = false; + prim.Body = IntPtr.Zero; + prim.m_disabled = true; + prim.IsPhysical = false; + } - public OdePrim getPrim(uint id) - { - lock (_prims) - { - if(_prims.ContainsKey(id)) - return _prims[id]; - else - return null; - } - } - public bool havePrim(OdePrim prm) - { - lock (_prims) - return _prims.ContainsKey(prm.LocalID); - } + } + prim.m_targetSpace = IntPtr.Zero; + if (!prim.RemoveGeom()) + m_log.Warn("[ODE SCENE]: Unable to remove prim from physics scene"); - public void changePrimID(OdePrim prim,uint oldID) - { - lock (_prims) - { - if(_prims.ContainsKey(oldID)) - _prims.Remove(oldID); - _prims[prim.LocalID] = prim; + lock (_prims) + _prims.Remove(prim); + + + if (SupportsNINJAJoints) + RemoveAllJointsConnectedToActorThreadLocked(prim); + } } } - - public bool haveActor(PhysicsActor actor) - { - if (actor is OdePrim) - { - lock (_prims) - return _prims.ContainsKey(((OdePrim)actor).LocalID); - } - else if (actor is OdeCharacter) - { - lock (_characters) - return _characters.Contains((OdeCharacter)actor); - } - return false; - } #endregion #region Space Separation Calculation /// - /// Called when a static prim moves or becomes static - /// Places the prim in a space one the static sub-spaces grid + /// Takes a space pointer and zeros out the array we're using to hold the spaces + /// + /// + private void resetSpaceArrayItemToZero(IntPtr pSpace) + { + for (int x = 0; x < staticPrimspace.GetLength(0); x++) + { + for (int y = 0; y < staticPrimspace.GetLength(1); y++) + { + if (staticPrimspace[x, y] == pSpace) + staticPrimspace[x, y] = IntPtr.Zero; + } + } + } + +// private void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY) +// { +// staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero; +// } + + /// + /// Called when a static prim moves. Allocates a space for the prim based on its position /// /// the pointer to the geom that moved /// the position that the geom moved to /// a pointer to the space it was in before it was moved. /// a pointer to the new space it's in - public IntPtr MoveGeomToStaticSpace(IntPtr geom, Vector3 pos, IntPtr currentspace) + internal IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace) { - // moves a prim into another static sub-space or from another space into a static sub-space - - // Called ODEPrim so + // Called from setting the Position and Size of an ODEPrim so // it's already in locked space. - if (geom == IntPtr.Zero) // shouldn't happen - return IntPtr.Zero; + // we don't want to remove the main space + // we don't need to test physical here because this function should + // never be called if the prim is physical(active) - // get the static sub-space for current position - IntPtr newspace = calculateSpaceForGeom(pos); - - if (newspace == currentspace) // if we are there all done - return newspace; - - // else remove it from its current space - if (currentspace != IntPtr.Zero && d.SpaceQuery(currentspace, geom)) + // All physical prim end up in the root space + //Thread.Sleep(20); + if (currentspace != space) { - if (d.GeomIsSpace(currentspace)) + //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString()); + //if (currentspace == IntPtr.Zero) + //{ + //int adfadf = 0; + //} + if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero) { - waitForSpaceUnlock(currentspace); - d.SpaceRemove(currentspace, geom); - - if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0) + if (d.GeomIsSpace(currentspace)) { - d.SpaceDestroy(currentspace); +// waitForSpaceUnlock(currentspace); + d.SpaceRemove(currentspace, geom); + } + else + { + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace + + " Geom:" + geom); } } else { - m_log.Info("[Physics]: Invalid or empty Space passed to 'MoveGeomToStaticSpace':" + currentspace + - " Geom:" + geom); + IntPtr sGeomIsIn = d.GeomGetSpace(geom); + if (sGeomIsIn != IntPtr.Zero) + { + if (d.GeomIsSpace(currentspace)) + { +// waitForSpaceUnlock(sGeomIsIn); + d.SpaceRemove(sGeomIsIn, geom); + } + else + { + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + + sGeomIsIn + " Geom:" + geom); + } + } + } + + //If there are no more geometries in the sub-space, we don't need it in the main space anymore + if (d.SpaceGetNumGeoms(currentspace) == 0) + { + if (currentspace != IntPtr.Zero) + { + if (d.GeomIsSpace(currentspace)) + { + d.SpaceRemove(space, currentspace); + // free up memory used by the space. + + resetSpaceArrayItemToZero(currentspace); + } + else + { + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + + currentspace + " Geom:" + geom); + } + } } } - else // odd currentspace is null or doesn't contain the geom? lets try the geom ideia of current space + else { - currentspace = d.GeomGetSpace(geom); - if (currentspace != IntPtr.Zero) + // this is a physical object that got disabled. ;.; + if (currentspace != IntPtr.Zero && geom != IntPtr.Zero) { - if (d.GeomIsSpace(currentspace)) + if (d.SpaceQuery(currentspace, geom)) { - waitForSpaceUnlock(currentspace); - d.SpaceRemove(currentspace, geom); - - if (d.SpaceGetSublevel(currentspace) > 2 && d.SpaceGetNumGeoms(currentspace) == 0) + if (d.GeomIsSpace(currentspace)) { - d.SpaceDestroy(currentspace); +// waitForSpaceUnlock(currentspace); + d.SpaceRemove(currentspace, geom); + } + else + { + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + + currentspace + " Geom:" + geom); + } + } + else + { + IntPtr sGeomIsIn = d.GeomGetSpace(geom); + if (sGeomIsIn != IntPtr.Zero) + { + if (d.GeomIsSpace(sGeomIsIn)) + { +// waitForSpaceUnlock(sGeomIsIn); + d.SpaceRemove(sGeomIsIn, geom); + } + else + { + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + + sGeomIsIn + " Geom:" + geom); + } } - } } } - // put the geom in the newspace - waitForSpaceUnlock(newspace); - d.SpaceAdd(newspace, geom); + // The routines in the Position and Size sections do the 'inserting' into the space, + // so all we have to do is make sure that the space that we're putting the prim into + // is in the 'main' space. + int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos); + IntPtr newspace = calculateSpaceForGeom(pos); + + if (newspace == IntPtr.Zero) + { + newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]); + d.HashSpaceSetLevels(newspace, HashspaceLow, HashspaceHigh); + } - // let caller know this newspace return newspace; } + /// + /// Creates a new space at X Y + /// + /// + /// + /// A pointer to the created space + internal IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY) + { + // 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); + d.SpaceSetSublevel(space, 1); + d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]); + + return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]; + } + /// /// Calculates the space the prim should be in by its position /// /// /// a pointer to the space. This could be a new space or reused space. - public IntPtr calculateSpaceForGeom(Vector3 pos) + internal IntPtr calculateSpaceForGeom(Vector3 pos) { - int x, y; - - if (pos.X < 0) - return staticPrimspaceOffRegion[0]; - - if (pos.Y < 0) - return staticPrimspaceOffRegion[2]; - - x = (int)(pos.X * spacesPerMeterX); - if (x > spaceGridMaxX) - return staticPrimspaceOffRegion[1]; - - y = (int)(pos.Y * spacesPerMeterY); - if (y > spaceGridMaxY) - return staticPrimspaceOffRegion[3]; - - return staticPrimspace[x, y]; + int[] xyspace = calculateSpaceArrayItemFromPos(pos); + //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString()); + return staticPrimspace[xyspace[0], xyspace[1]]; } - - #endregion - /// - /// Called to queue a change to a actor - /// to use in place of old taint mechanism so changes do have a time sequence + /// Holds the space allocation logic /// - - public void AddChange(PhysicsActor actor, changes what, Object arg) + /// + /// an array item based on the position + internal int[] calculateSpaceArrayItemFromPos(Vector3 pos) { - ODEchangeitem item = new ODEchangeitem(); - item.actor = actor; - item.what = what; - item.arg = arg; - ChangesQueue.Enqueue(item); + int[] returnint = new int[2]; + + returnint[0] = (int) (pos.X * spacesPerMeterX); + + if (returnint[0] > spaceGridMaxX) + returnint[0] = spaceGridMaxX; + if (returnint[0] < 0) + returnint[0] = 0; + + returnint[1] = (int)(pos.Y * spacesPerMeterY); + if (returnint[1] > spaceGridMaxY) + returnint[1] = spaceGridMaxY; + if (returnint[1] < 0) + returnint[1] = 0; + + return returnint; + } + + #endregion + + /// + /// Routine to figure out if we need to mesh this prim with our mesher + /// + /// + /// + internal bool needsMeshing(PrimitiveBaseShape pbs) + { + // most of this is redundant now as the mesher will return null if it cant mesh a prim + // but we still need to check for sculptie meshing being enabled so this is the most + // convenient place to do it for now... + + // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f) + // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString()); + int iPropertiesNotSupportedDefault = 0; + + if (pbs.SculptEntry && !meshSculptedPrim) + { +#if SPAM + m_log.Warn("NonMesh"); +#endif + return false; + } + + // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim + if (!forceSimplePrimMeshing && !pbs.SculptEntry) + { + if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) + || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 + && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) + { + + if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 + && pbs.ProfileHollow == 0 + && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 + && pbs.PathBegin == 0 && pbs.PathEnd == 0 + && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 + && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 + && pbs.PathShearX == 0 && pbs.PathShearY == 0) + { +#if SPAM + m_log.Warn("NonMesh"); +#endif + return false; + } + } + } + + if (pbs.ProfileHollow != 0) + iPropertiesNotSupportedDefault++; + + if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) + iPropertiesNotSupportedDefault++; + + if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) + iPropertiesNotSupportedDefault++; + + if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0) + iPropertiesNotSupportedDefault++; + + if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100)) + iPropertiesNotSupportedDefault++; + + if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0)) + iPropertiesNotSupportedDefault++; + + if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) + iPropertiesNotSupportedDefault++; + + if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X)) + iPropertiesNotSupportedDefault++; + + if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1) + iPropertiesNotSupportedDefault++; + + // test for torus + if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square) + { + if (pbs.PathCurve == (byte)Extrusion.Curve1) + { + iPropertiesNotSupportedDefault++; + } + } + else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) + { + if (pbs.PathCurve == (byte)Extrusion.Straight) + { + iPropertiesNotSupportedDefault++; + } + + // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits + else if (pbs.PathCurve == (byte)Extrusion.Curve1) + { + iPropertiesNotSupportedDefault++; + } + } + else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) + { + if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) + { + iPropertiesNotSupportedDefault++; + } + } + else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) + { + if (pbs.PathCurve == (byte)Extrusion.Straight) + { + iPropertiesNotSupportedDefault++; + } + else if (pbs.PathCurve == (byte)Extrusion.Curve1) + { + iPropertiesNotSupportedDefault++; + } + } + + if (pbs.SculptEntry && meshSculptedPrim) + iPropertiesNotSupportedDefault++; + + if (iPropertiesNotSupportedDefault == 0) + { +#if SPAM + m_log.Warn("NonMesh"); +#endif + return false; + } +#if SPAM + m_log.Debug("Mesh"); +#endif + return true; } /// /// 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 (actor is OdePrim) + { + OdePrim taintedprim = ((OdePrim)actor); + lock (_taintedPrims) + _taintedPrims.Add(taintedprim); + } + else if (actor is OdeCharacter) + { + OdeCharacter taintedchar = ((OdeCharacter)actor); + lock (_taintedActors) + { + _taintedActors.Add(taintedchar); + if (taintedchar.bad) + m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid); + } + } } // does all pending changes generated during region load process @@ -1573,315 +2625,319 @@ namespace OpenSim.Region.PhysicsModule.ubOde { if (world == IntPtr.Zero) { - ChangesQueue.Clear(); + _taintedPrims.Clear();; return; } - d.AllocateODEDataForThread(~0U); - - ODEchangeitem item; - int donechanges = 0; - if (ChangesQueue.Count > 0) + if (_taintedPrims.Count > 0) { - m_log.InfoFormat("[ubOde] start processing pending actor operations"); + + m_log.InfoFormat("[Ode] start processing pending actor operations"); int tstart = Util.EnvironmentTickCount(); - while (ChangesQueue.Dequeue(out item)) + d.AllocateODEDataForThread(0); + + lock (_taintedPrims) { - if (item.actor != null) + foreach (OdePrim prim in _taintedPrims) { - try - { - if (item.actor is OdeCharacter) - ((OdeCharacter)item.actor).DoAChange(item.what, item.arg); - else if (((OdePrim)item.actor).DoAChange(item.what, item.arg)) - RemovePrimThreadLocked((OdePrim)item.actor); - } - catch - { - m_log.WarnFormat("[PHYSICS]: Operation failed for a actor {0} {1}", - item.actor.Name, item.what.ToString()); - } + if (prim.m_taintremove) + RemovePrimThreadLocked(prim); + else + prim.ProcessTaints(); + + prim.m_collisionscore = 0; + donechanges++; } - donechanges++; + _taintedPrims.Clear(); } + int time = Util.EnvironmentTickCountSubtract(tstart); - m_log.InfoFormat("[ubOde] finished {0} operations in {1}ms", donechanges, time); + m_log.InfoFormat("[Ode] finished {0} operations in {1}ms", donechanges, time); } - m_log.InfoFormat("[ubOde] {0} prim actors loaded",_prims.Count); + m_log.InfoFormat("[Ode] {0} prim actors loaded",_prims.Count); } } + /// /// This is our main simulate loop + /// + /// /// It's thread locked by a Mutex in the scene. /// It holds Collisions, it instructs ODE to step through the physical reactions /// It moves the objects around in memory /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup) - /// + /// /// - /// - public override float Simulate(float reqTimeStep) + /// The number of frames simulated over that period. + public override float Simulate(float timeStep) { - DateTime now = DateTime.UtcNow; - TimeSpan timedif = now - m_lastframe; - float timeStep = (float)timedif.TotalSeconds; - m_lastframe = now; - - // acumulate time so we can reduce error - step_time += timeStep; + if (!_worldInitialized) + return 1.0f; - if (step_time < HalfOdeStep) - return 0; + int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0; + int tempTick = 0, tempTick2 = 0; - if (framecount < 0) + if (framecount >= int.MaxValue) framecount = 0; framecount++; -// checkThread(); - int nodeframes = 0; float fps = 0; - lock (SimulationLock) - lock(OdeLock) + step_time += timeStep; + + float HalfOdeStep = ODE_STEPSIZE * 0.5f; + if (step_time < HalfOdeStep) + return 0; + + + // We change _collisionEventPrimChanges to avoid locking _collisionEventPrim itself and causing potential + // deadlock if the collision event tries to lock something else later on which is already locked by a + // caller that is adding or removing the collision event. + lock (m_collisionEventActorsChanges) { - if (world == IntPtr.Zero) + foreach (KeyValuePair kvp in m_collisionEventActorsChanges) { - ChangesQueue.Clear(); - return 0; + if (kvp.Value == null) + m_collisionEventActors.Remove(kvp.Key); + else + m_collisionEventActors[kvp.Key] = kvp.Value; } - ODEchangeitem item; - -// d.WorldSetQuickStepNumIterations(world, curphysiteractions); + m_collisionEventActorsChanges.Clear(); + } - int loopstartMS = Util.EnvironmentTickCount(); - int looptimeMS = 0; - int changestimeMS = 0; - int maxChangestime = (int)(reqTimeStep * 500f); // half the time - int maxLoopTime = (int)(reqTimeStep * 1200f); // 1.2 the time - + if (SupportsNINJAJoints) + { + DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks + CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks + } + + + lock (OdeLock) + { d.AllocateODEDataForThread(~0U); - - if (ChangesQueue.Count > 0) - { - while (ChangesQueue.Dequeue(out item)) - { - if (item.actor != null) - { - try - { - if (item.actor is OdeCharacter) - ((OdeCharacter)item.actor).DoAChange(item.what, item.arg); - else if (((OdePrim)item.actor).DoAChange(item.what, item.arg)) - RemovePrimThreadLocked((OdePrim)item.actor); - } - catch - { - m_log.WarnFormat("[PHYSICS]: doChange failed for a actor {0} {1}", - item.actor.Name, item.what.ToString()); - } - } - changestimeMS = Util.EnvironmentTickCountSubtract(loopstartMS); - if (changestimeMS > maxChangestime) - break; - } - } - // do simulation taking at most 150ms total time including changes - while (step_time > HalfOdeStep) + while (step_time > HalfOdeStep) { try { - // clear pointer/counter to contacts to pass into joints - m_global_contactcount = 0; + if (CollectStats) + tempTick = Util.EnvironmentTickCount(); + lock (_taintedActors) + { + foreach (OdeCharacter character in _taintedActors) + character.ProcessTaints(); + + _taintedActors.Clear(); + } + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + lock (_taintedPrims) + { + foreach (OdePrim prim in _taintedPrims) + { + if (prim.m_taintremove) + { +// Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name); + RemovePrimThreadLocked(prim); + } + else + { +// Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name); + prim.ProcessTaints(); + } + + prim.m_collisionscore = 0; + + // This loop can block up the Heartbeat for a very long time on large regions. + // We need to let the Watchdog know that the Heartbeat is not dead + // NOTE: This is currently commented out, but if things like OAR loading are + // timing the heartbeat out we will need to uncomment it + //Watchdog.UpdateThread(); + } + + if (SupportsNINJAJoints) + SimulatePendingNINJAJoints(); + + _taintedPrims.Clear(); + } + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } // Move characters - lock (_characters) + foreach (OdeCharacter actor in _characters) + actor.Move(defects); + + if (defects.Count != 0) { - List defects = new List(); - foreach (OdeCharacter actor in _characters) + foreach (OdeCharacter actor in defects) { - if (actor != null) - actor.Move(defects); - } - if (defects.Count != 0) - { - foreach (OdeCharacter defect in defects) - { - RemoveCharacter(defect); - } - defects.Clear(); + m_log.ErrorFormat( + "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when moving", + actor.Name, actor.LocalID, PhysicsSceneName); + + RemoveCharacter(actor); + actor.DestroyOdeStructures(); } + + defects.Clear(); + } + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; } // Move other active objects - lock (_activegroups) + foreach (OdePrim prim in _activeprims) { - foreach (OdePrim aprim in _activegroups) - { - aprim.Move(); - } + prim.m_collisionscore = 0; + prim.Move(timeStep); } - + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + m_rayCastManager.ProcessQueuedRequests(); - collision_optimized(); - List sleepers = new List(); - - foreach (PhysicsActor obj in _collisionEventPrim) + if (CollectStats) { - if (obj == null) - continue; + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + collision_optimized(); + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + foreach (PhysicsActor obj in m_collisionEventActors.Values) + { + // m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID); switch ((ActorTypes)obj.PhysicsActorType) { case ActorTypes.Agent: OdeCharacter cobj = (OdeCharacter)obj; - cobj.SendCollisions((int)(odetimestepMS)); + cobj.AddCollisionFrameTime(100); + cobj.SendCollisions(); break; case ActorTypes.Prim: OdePrim pobj = (OdePrim)obj; - if (!pobj.m_outbounds) - { - pobj.SendCollisions((int)(odetimestepMS)); - if(pobj.Body != IntPtr.Zero && !pobj.m_isSelected && - !pobj.m_disabled && !pobj.m_building && - !d.BodyIsEnabled(pobj.Body)) - sleepers.Add(pobj); - } + pobj.SendCollisions(); break; } } - foreach(OdePrim prm in sleepers) - prm.SleeperAddCollisionEvents(); - sleepers.Clear(); +// if (m_global_contactcount > 0) +// m_log.DebugFormat( +// "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount); - lock(_collisionEventPrimRemove) + m_global_contactcount = 0; + + if (CollectStats) { - foreach (PhysicsActor obj in _collisionEventPrimRemove) - _collisionEventPrim.Remove(obj); - - _collisionEventPrimRemove.Clear(); + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; } - // do a ode simulation step - d.WorldQuickStep(world, ODE_STEPSIZE); + lock(SimulationLock) + d.WorldQuickStep(world, ODE_STEPSIZE); + + if (CollectStats) + m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); + d.JointGroupEmpty(contactgroup); - - // update managed ideia of physical data and do updates to core - /* - lock (_characters) - { - 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); - - actor.UpdatePositionAndVelocity(); - } - } - } - */ - - lock (_activegroups) - { - { - foreach (OdePrim actor in _activegroups) - { - if (actor.IsPhysical) - { - actor.UpdatePositionAndVelocity(framecount); - } - } - } - } } catch (Exception e) { - m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e); -// ode.dunlock(world); + m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e); } step_time -= ODE_STEPSIZE; - nodeframes++; - - looptimeMS = Util.EnvironmentTickCountSubtract(loopstartMS); - if (looptimeMS > maxLoopTime) - break; + fps += ODE_STEPSIZE; } - lock (_badCharacter) - { - if (_badCharacter.Count > 0) - { - foreach (OdeCharacter chr in _badCharacter) - { - RemoveCharacter(chr); - } + if (CollectStats) + tempTick = Util.EnvironmentTickCount(); - _badCharacter.Clear(); + foreach (OdeCharacter actor in _characters) + { + if (actor.bad) + m_log.ErrorFormat("[ODE SCENE]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); + + actor.UpdatePositionAndVelocity(defects); + } + + if (defects.Count != 0) + { + foreach (OdeCharacter actor in defects) + { + m_log.ErrorFormat( + "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when updating position and velocity", + actor.Name, actor.LocalID, PhysicsSceneName); + + RemoveCharacter(actor); + actor.DestroyOdeStructures(); + } + + defects.Clear(); + } + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + //if (timeStep < 0.2f) + + foreach (OdePrim prim in _activeprims) + { + if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag)) + { + prim.UpdatePositionAndVelocity(); + + if (SupportsNINJAJoints) + SimulateActorPendingJoints(prim); } } - timedif = now - m_lastMeshExpire; + if (CollectStats) + m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); - if (timedif.Seconds > 10) - { - mesher.ExpireReleaseMeshs(); - m_lastMeshExpire = now; - } + //DumpJointInfo(); -// information block for in debug breakpoint only -/* - int ntopactivegeoms = d.SpaceGetNumGeoms(ActiveSpace); - int ntopstaticgeoms = d.SpaceGetNumGeoms(StaticSpace); - int ngroundgeoms = d.SpaceGetNumGeoms(GroundSpace); - - int nactivegeoms = 0; - int nactivespaces = 0; - - int nstaticgeoms = 0; - int nstaticspaces = 0; - IntPtr sp; - - for (int i = 0; i < ntopactivegeoms; i++) - { - sp = d.SpaceGetGeom(ActiveSpace, i); - if (d.GeomIsSpace(sp)) - { - nactivespaces++; - nactivegeoms += d.SpaceGetNumGeoms(sp); - } - else - nactivegeoms++; - } - - for (int i = 0; i < ntopstaticgeoms; i++) - { - sp = d.SpaceGetGeom(StaticSpace, i); - if (d.GeomIsSpace(sp)) - { - nstaticspaces++; - nstaticgeoms += d.SpaceGetNumGeoms(sp); - } - else - nstaticgeoms++; - } - - int ntopgeoms = d.SpaceGetNumGeoms(TopSpace); - - int totgeoms = nstaticgeoms + nactivegeoms + ngroundgeoms + 1; // one ray - int nbodies = d.NTotalBodies; - int ngeoms = d.NTotalGeoms; -*/ // Finished with all sim stepping. If requested, dump world state to file for debugging. // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? @@ -1900,30 +2956,257 @@ namespace OpenSim.Region.PhysicsModule.ubOde d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); } - - fps = (float)nodeframes * ODE_STEPSIZE / reqTimeStep; - if(step_time < HalfOdeStep) - m_timeDilation = 1.0f; - else if (step_time > m_SkipFramesAtms) + latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun); + + // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics + // has a max of 100 ms to run theoretically. + // If the main loop stalls, it calls Simulate later which makes the tick count ms larger. + // If Physics stalls, it takes longer which makes the tick count ms larger. + + if (latertickcount < 100) { - // if we lag too much skip frames - m_timeDilation = 0.0f; - step_time = 0; - m_lastframe = DateTime.UtcNow; // skip also the time lost + m_timeDilation = 1.0f; } else { - m_timeDilation = ODE_STEPSIZE / step_time; - if (m_timeDilation > 1) - m_timeDilation = 1; + m_timeDilation = 100f / latertickcount; + //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f); } + + tickCountFrameRun = Util.EnvironmentTickCount(); + + if (CollectStats) + m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick); } + fps *= 1.0f/timeStep; return fps; } /// + /// Simulate pending NINJA joints. + /// + /// + /// Called by the main Simulate() loop if NINJA joints are active. Should not be called from anywhere else. + /// + private void SimulatePendingNINJAJoints() + { + // Create pending joints, if possible + + // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating + // a joint requires specifying the body id of both involved bodies + if (pendingJoints.Count > 0) + { + List successfullyProcessedPendingJoints = new List(); + //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints"); + foreach (PhysicsJoint joint in pendingJoints) + { + //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams); + string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); + List jointBodies = new List(); + bool allJointBodiesAreReady = true; + foreach (string jointParam in jointParams) + { + if (jointParam == "NULL") + { + //DoJointErrorMessage(joint, "attaching NULL joint to world"); + jointBodies.Add(IntPtr.Zero); + } + else + { + //DoJointErrorMessage(joint, "looking for prim name: " + jointParam); + bool foundPrim = false; + lock (_prims) + { + foreach (OdePrim prim in _prims) // FIXME: inefficient + { + if (prim.SOPName == jointParam) + { + //DoJointErrorMessage(joint, "found for prim name: " + jointParam); + if (prim.IsPhysical && prim.Body != IntPtr.Zero) + { + jointBodies.Add(prim.Body); + foundPrim = true; + break; + } + else + { + DoJointErrorMessage(joint, "prim name " + jointParam + + " exists but is not (yet) physical; deferring joint creation. " + + "IsPhysical property is " + prim.IsPhysical + + " and body is " + prim.Body); + foundPrim = false; + break; + } + } + } + } + if (foundPrim) + { + // all is fine + } + else + { + allJointBodiesAreReady = false; + break; + } + } + } + + if (allJointBodiesAreReady) + { + //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams); + if (jointBodies[0] == jointBodies[1]) + { + DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams); + } + else + { + switch (joint.Type) + { + case PhysicsJointType.Ball: + { + IntPtr odeJoint; + //DoJointErrorMessage(joint, "ODE creating ball joint "); + odeJoint = d.JointCreateBall(world, IntPtr.Zero); + //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); + d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); + //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position); + d.JointSetBallAnchor(odeJoint, + joint.Position.X, + joint.Position.Y, + joint.Position.Z); + //DoJointErrorMessage(joint, "ODE joint setting OK"); + //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: "); + //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment")); + //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: "); + //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment")); + + if (joint is OdePhysicsJoint) + { + ((OdePhysicsJoint)joint).jointID = odeJoint; + } + else + { + DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); + } + } + break; + case PhysicsJointType.Hinge: + { + IntPtr odeJoint; + //DoJointErrorMessage(joint, "ODE creating hinge joint "); + odeJoint = d.JointCreateHinge(world, IntPtr.Zero); + //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); + d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); + //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position); + d.JointSetHingeAnchor(odeJoint, + joint.Position.X, + joint.Position.Y, + joint.Position.Z); + // We use the orientation of the x-axis of the joint's coordinate frame + // as the axis for the hinge. + + // Therefore, we must get the joint's coordinate frame based on the + // joint.Rotation field, which originates from the orientation of the + // joint's proxy object in the scene. + + // The joint's coordinate frame is defined as the transformation matrix + // that converts a vector from joint-local coordinates into world coordinates. + // World coordinates are defined as the XYZ coordinate system of the sim, + // as shown in the top status-bar of the viewer. + + // Once we have the joint's coordinate frame, we extract its X axis (AtAxis) + // and use that as the hinge axis. + + //joint.Rotation.Normalize(); + Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation); + + // Now extract the X axis of the joint's coordinate frame. + + // Do not try to use proxyFrame.AtAxis or you will become mired in the + // tar pit of transposed, inverted, and generally messed-up orientations. + // (In other words, Matrix4.AtAxis() is borked.) + // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness + + // Instead, compute the X axis of the coordinate frame by transforming + // the (1,0,0) vector. At least that works. + + //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame); + Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame); + //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis); + //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis); + d.JointSetHingeAxis(odeJoint, + jointAxis.X, + jointAxis.Y, + jointAxis.Z); + //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f); + if (joint is OdePhysicsJoint) + { + ((OdePhysicsJoint)joint).jointID = odeJoint; + } + else + { + DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); + } + } + break; + } + successfullyProcessedPendingJoints.Add(joint); + } + } + else + { + DoJointErrorMessage(joint, "joint could not yet be created; still pending"); + } + } + + foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints) + { + //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams); + //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending"); + InternalRemovePendingJoint(successfullyProcessedJoint); + //DoJointErrorMessage(successfullyProcessedJoint, "adding to active"); + InternalAddActiveJoint(successfullyProcessedJoint); + //DoJointErrorMessage(successfullyProcessedJoint, "done"); + } + } + } + + /// + /// Simulate the joint proxies of a NINJA actor. + /// + /// + /// Called as part of the Simulate() loop if NINJA physics is active. Must only be called from there. + /// + /// + private void SimulateActorPendingJoints(OdePrim actor) + { + // If an actor moved, move its joint proxy objects as well. + // There seems to be an event PhysicsActor.OnPositionUpdate that could be used + // for this purpose but it is never called! So we just do the joint + // movement code here. + + if (actor.SOPName != null && + joints_connecting_actor.ContainsKey(actor.SOPName) && + joints_connecting_actor[actor.SOPName] != null && + joints_connecting_actor[actor.SOPName].Count > 0) + { + foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName]) + { + if (affectedJoint.IsInPhysicsEngine) + { + DoJointMoved(affectedJoint); + } + else + { + DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams); + } + } + } + } + public override void GetResults() { } @@ -1931,272 +3214,33 @@ namespace OpenSim.Region.PhysicsModule.ubOde public override bool IsThreaded { // for now we won't be multithreaded - get { return (false); } - } - - public float GetTerrainHeightAtXY(float x, float y) - { - if (TerrainGeom == IntPtr.Zero) - return 0f; - - if (TerrainHeightFieldHeight == null || TerrainHeightFieldHeight.Length == 0) - return 0f; - - // TerrainHeightField for ODE as offset 1m - x += 1f; - y += 1f; - - // make position fit into array - if (x < 0) - x = 0; - if (y < 0) - y = 0; - - // integer indexs - int ix; - int iy; - // interpolators offset - float dx; - float dy; - - int regsizeX = (int)m_regionWidth + 3; // map size see setterrain number of samples - int regsizeY = (int)m_regionHeight + 3; // map size see setterrain number of samples - int regsize = regsizeX; - - if (m_OSOdeLib) - { - if (x < regsizeX - 1) - { - ix = (int)x; - dx = x - (float)ix; - } - else // out world use external height - { - ix = regsizeX - 2; - dx = 0; - } - if (y < regsizeY - 1) - { - iy = (int)y; - dy = y - (float)iy; - } - else - { - iy = regsizeY - 2; - dy = 0; - } - } - else - { - // we still have square fixed size regions - // also flip x and y because of how map is done for ODE fliped axis - // so ix,iy,dx and dy are inter exchanged - - regsize = regsizeY; - - if (x < regsizeX - 1) - { - iy = (int)x; - dy = x - (float)iy; - } - else // out world use external height - { - iy = regsizeX - 2; - dy = 0; - } - if (y < regsizeY - 1) - { - ix = (int)y; - dx = y - (float)ix; - } - else - { - ix = regsizeY - 2; - dx = 0; - } - } - - float h0; - float h1; - float h2; - - iy *= regsize; - iy += ix; // all indexes have iy + ix - - float[] heights = TerrainHeightFieldHeight; - /* - if ((dx + dy) <= 1.0f) - { - h0 = ((float)heights[iy]); // 0,0 vertice - h1 = (((float)heights[iy + 1]) - h0) * dx; // 1,0 vertice minus 0,0 - h2 = (((float)heights[iy + regsize]) - h0) * dy; // 0,1 vertice minus 0,0 - } - else - { - h0 = ((float)heights[iy + regsize + 1]); // 1,1 vertice - h1 = (((float)heights[iy + 1]) - h0) * (1 - dy); // 1,1 vertice minus 1,0 - h2 = (((float)heights[iy + regsize]) - h0) * (1 - dx); // 1,1 vertice minus 0,1 - } - */ - h0 = ((float)heights[iy]); // 0,0 vertice - - if (dy>dx) - { - iy += regsize; - h2 = (float)heights[iy]; // 0,1 vertice - h1 = (h2 - h0) * dy; // 0,1 vertice minus 0,0 - h2 = ((float)heights[iy + 1] - h2) * dx; // 1,1 vertice minus 0,1 - } - else - { - iy++; - h2 = (float)heights[iy]; // vertice 1,0 - h1 = (h2 - h0) * dx; // 1,0 vertice minus 0,0 - h2 = (((float)heights[iy + regsize]) - h2) * dy; // 1,1 vertice minus 1,0 - } - - return h0 + h1 + h2; - } - - public Vector3 GetTerrainNormalAtXY(float x, float y) - { - Vector3 norm = new Vector3(0, 0, 1); - - if (TerrainGeom == IntPtr.Zero) - return norm; - - if (TerrainHeightFieldHeight == null || TerrainHeightFieldHeight.Length == 0) - return norm; - - // TerrainHeightField for ODE as offset 1m - x += 1f; - y += 1f; - - // make position fit into array - if (x < 0) - x = 0; - if (y < 0) - y = 0; - - // integer indexs - int ix; - int iy; - // interpolators offset - float dx; - float dy; - - int regsizeX = (int)m_regionWidth + 3; // map size see setterrain number of samples - int regsizeY = (int)m_regionHeight + 3; // map size see setterrain number of samples - int regsize = regsizeX; - - int xstep = 1; - int ystep = regsizeX; - bool firstTri = false; - - if (m_OSOdeLib) - { - if (x < regsizeX - 1) - { - ix = (int)x; - dx = x - (float)ix; - } - else // out world use external height - { - ix = regsizeX - 2; - dx = 0; - } - if (y < regsizeY - 1) - { - iy = (int)y; - dy = y - (float)iy; - } - else - { - iy = regsizeY - 2; - dy = 0; - } - firstTri = dy > dx; - } - - else - { - xstep = regsizeY; - ystep = 1; - regsize = regsizeY; - - // we still have square fixed size regions - // also flip x and y because of how map is done for ODE fliped axis - // so ix,iy,dx and dy are inter exchanged - if (x < regsizeX - 1) - { - iy = (int)x; - dy = x - (float)iy; - } - else // out world use external height - { - iy = regsizeX - 2; - dy = 0; - } - if (y < regsizeY - 1) - { - ix = (int)y; - dx = y - (float)ix; - } - else - { - ix = regsizeY - 2; - dx = 0; - } - firstTri = dx > dy; - } - - float h0; - float h1; - float h2; - - iy *= regsize; - iy += ix; // all indexes have iy + ix - - float[] heights = TerrainHeightFieldHeight; - - if (firstTri) - { - h1 = ((float)heights[iy]); // 0,0 vertice - iy += ystep; - h0 = (float)heights[iy]; // 0,1 - h2 = (float)heights[iy+xstep]; // 1,1 vertice - norm.X = h0 - h2; - norm.Y = h1 - h0; - } - else - { - h2 = ((float)heights[iy]); // 0,0 vertice - iy += xstep; - h0 = ((float)heights[iy]); // 1,0 vertice - h1 = (float)heights[iy+ystep]; // vertice 1,1 - norm.X = h2 - h0; - norm.Y = h0 - h1; - } - norm.Z = 1; - norm.Normalize(); - return norm; + get { return false; } } public override void SetTerrain(float[] heightMap) { - if (m_OSOdeLib) - OSSetTerrain(heightMap); + if (m_worldOffset != Vector3.Zero && m_parentScene != null) + { + if (m_parentScene is OdeScene) + { + ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset); + } + } else - OriSetTerrain(heightMap); + { + SetTerrain(heightMap, m_worldOffset); + } } - public void OriSetTerrain(float[] heightMap) + private void SetTerrain(float[] heightMap, Vector3 pOffset) { - // assumes 1m size grid and constante size square regions - // needs to know about sims around in future + int startTime = Util.EnvironmentTickCount(); + m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0} with offset {1}", PhysicsSceneName, pOffset); + float[] _heightmap; + // ok im lasy this are just a aliases uint regionsizeX = m_regionWidth; uint regionsizeY = m_regionHeight; @@ -2214,7 +3258,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde const float thickness = 10f; const int wrap = 0; - + float hfmin = float.MaxValue; float hfmax = float.MinValue; float val; @@ -2223,11 +3267,13 @@ namespace OpenSim.Region.PhysicsModule.ubOde uint maxXX = regionsizeX - 1; uint maxYY = regionsizeY - 1; + // flipping map adding one margin all around so things don't fall in edges uint xt = 0; xx = 0; + for (uint x = 0; x < heightmapWidthSamples; x++) { if (x > 1 && xx < maxXX) @@ -2240,7 +3286,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde val = heightMap[yy + xx]; if (val < 0.0f) - val = 0.0f; // no neg terrain as in chode + val = 0.0f; _heightmap[xt + y] = val; if (hfmin > val) @@ -2255,164 +3301,69 @@ namespace OpenSim.Region.PhysicsModule.ubOde { d.AllocateODEDataForThread(~0U); - if (TerrainGeom != IntPtr.Zero) + IntPtr GroundGeom = IntPtr.Zero; + if (RegionTerrain.TryGetValue(pOffset, out GroundGeom)) { - actor_name_map.Remove(TerrainGeom); - d.GeomDestroy(TerrainGeom); + RegionTerrain.Remove(pOffset); + if (GroundGeom != IntPtr.Zero) + { + if (TerrainHeightFieldHeights.ContainsKey(GroundGeom)) + { + TerrainHeightFieldHeights.Remove(GroundGeom); + } + d.SpaceRemove(space, GroundGeom); + d.GeomDestroy(GroundGeom); + } } - - if (TerrainHeightFieldHeightsHandler.IsAllocated) - TerrainHeightFieldHeightsHandler.Free(); - IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); - - TerrainHeightFieldHeightsHandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned); - - d.GeomHeightfieldDataBuildSingle(HeightmapData, TerrainHeightFieldHeightsHandler.AddrOfPinnedObject(), 0, - heightmapHeight, heightmapWidth , - (int)heightmapHeightSamples, (int)heightmapWidthSamples, scale, - offset, thickness, wrap); + d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, + heightmapWidth, heightmapHeight, + (int)heightmapWidthSamples, + (int)heightmapHeightSamples, + scale, offset, thickness, wrap); d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); - - TerrainGeom = d.CreateHeightfield(GroundSpace, HeightmapData, 1); - - if (TerrainGeom != IntPtr.Zero) + GroundGeom = d.CreateHeightfield(space, HeightmapData, 1); + if (GroundGeom != IntPtr.Zero) { - d.GeomSetCategoryBits(TerrainGeom, (uint)(CollisionCategories.Land)); - d.GeomSetCollideBits(TerrainGeom, 0); + d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land)); + d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space)); - PhysicsActor pa = new NullPhysicsActor(); - pa.Name = "Terrain"; - pa.PhysicsActorType = (int)ActorTypes.Ground; - actor_name_map[TerrainGeom] = pa; - -// geom_name_map[GroundGeom] = "Terrain"; - - d.Quaternion q = new d.Quaternion(); - q.X = 0.5f; - q.Y = 0.5f; - q.Z = 0.5f; - q.W = 0.5f; - - d.GeomSetQuaternion(TerrainGeom, ref q); - d.GeomSetPosition(TerrainGeom, m_regionWidth * 0.5f, m_regionHeight * 0.5f, 0.0f); - TerrainHeightFieldHeight = _heightmap; } - else - TerrainHeightFieldHeightsHandler.Free(); - } - } + geom_name_map[GroundGeom] = "Terrain"; - public void OSSetTerrain(float[] heightMap) - { - // assumes 1m size grid and constante size square regions - // needs to know about sims around in future + d.Matrix3 R = new d.Matrix3(); - float[] _heightmap; + Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); + Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f); - uint regionsizeX = m_regionWidth; - uint regionsizeY = m_regionHeight; + q1 = q1 * q2; + Vector3 v3; + float angle; + q1.GetAxisAngle(out v3, out angle); - uint heightmapWidth = regionsizeX + 2; - uint heightmapHeight = regionsizeY + 2; - - uint heightmapWidthSamples = heightmapWidth + 1; - uint heightmapHeightSamples = heightmapHeight + 1; - - _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples]; - - - float hfmin = float.MaxValue; -// float hfmax = float.MinValue; - float val; - - - uint maxXX = regionsizeX - 1; - uint maxYY = regionsizeY - 1; - // adding one margin all around so things don't fall in edges - - uint xx; - uint yy = 0; - uint yt = 0; - - for (uint y = 0; y < heightmapHeightSamples; y++) - { - if (y > 1 && y < maxYY) - yy += regionsizeX; - xx = 0; - for (uint x = 0; x < heightmapWidthSamples; x++) + d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); + d.GeomSetRotation(GroundGeom, ref R); + d.GeomSetPosition(GroundGeom, pOffset.X + regionsizeX * 0.5f, pOffset.Y + regionsizeY * 0.5f, 0.0f); + IntPtr testGround = IntPtr.Zero; + if (RegionTerrain.TryGetValue(pOffset, out testGround)) { - if (x > 1 && x < maxXX) - xx++; - - val = heightMap[yy + xx]; - if (val < 0.0f) - val = 0.0f; // no neg terrain as in chode - _heightmap[yt + x] = val; - - if (hfmin > val) - hfmin = val; -// if (hfmax < val) -// hfmax = val; + RegionTerrain.Remove(pOffset); } - yt += heightmapWidthSamples; + RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); + TerrainHeightFieldHeights.Add(GroundGeom,_heightmap); } - lock (OdeLock) - { - if (TerrainGeom != IntPtr.Zero) - { - actor_name_map.Remove(TerrainGeom); - d.GeomDestroy(TerrainGeom); - } - - if (TerrainHeightFieldHeightsHandler.IsAllocated) - TerrainHeightFieldHeightsHandler.Free(); - - TerrainHeightFieldHeight = null; - - IntPtr HeightmapData = d.GeomOSTerrainDataCreate(); - - const int wrap = 0; - float thickness = hfmin; - if (thickness < 0) - thickness = 1; - - TerrainHeightFieldHeightsHandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned); - - d.GeomOSTerrainDataBuild(HeightmapData, TerrainHeightFieldHeightsHandler.AddrOfPinnedObject(), 0, 1.0f, - (int)heightmapWidthSamples, (int)heightmapHeightSamples, - thickness, wrap); - -// d.GeomOSTerrainDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); - TerrainGeom = d.CreateOSTerrain(GroundSpace, HeightmapData, 1); - if (TerrainGeom != IntPtr.Zero) - { - d.GeomSetCategoryBits(TerrainGeom, (uint)(CollisionCategories.Land)); - d.GeomSetCollideBits(TerrainGeom, 0); - - PhysicsActor pa = new NullPhysicsActor(); - pa.Name = "Terrain"; - pa.PhysicsActorType = (int)ActorTypes.Ground; - actor_name_map[TerrainGeom] = pa; - -// geom_name_map[GroundGeom] = "Terrain"; - - d.GeomSetPosition(TerrainGeom, m_regionWidth * 0.5f, m_regionHeight * 0.5f, 0.0f); - TerrainHeightFieldHeight = _heightmap; - } - else - TerrainHeightFieldHeightsHandler.Free(); - } + m_log.DebugFormat( + "[ODE SCENE]: Setting terrain for {0} took {1}ms", PhysicsSceneName, Util.EnvironmentTickCountSubtract(startTime)); } public override void DeleteTerrain() { } - public float GetWaterLevel() + internal float GetWaterLevel() { return waterlevel; } @@ -2422,18 +3373,18 @@ namespace OpenSim.Region.PhysicsModule.ubOde waterlevel = baseheight; } + [HandleProcessCorruptedStateExceptions] public override void Dispose() { - lock (OdeLock) + lock(SimulationLock) + lock(OdeLock) { - - if (world == IntPtr.Zero) + if(world == IntPtr.Zero) return; - d.AllocateODEDataForThread(~0U); + _worldInitialized = false; - if (m_meshWorker != null) - m_meshWorker.Stop(); + d.AllocateODEDataForThread(~0U); if (m_rayCastManager != null) { @@ -2443,49 +3394,37 @@ namespace OpenSim.Region.PhysicsModule.ubOde lock (_prims) { - ChangesQueue.Clear(); - foreach (OdePrim prm in _prims.Values) + foreach (OdePrim prm in _prims) { - prm.DoAChange(changes.Remove, null); - _collisionEventPrim.Remove(prm); + RemovePrim(prm); } - _prims.Clear(); } - OdeCharacter[] chtorem; - lock (_characters) + //foreach (OdeCharacter act in _characters) + //{ + //RemoveAvatar(act); + //} + IntPtr GroundGeom = IntPtr.Zero; + if (RegionTerrain.TryGetValue(m_worldOffset, out GroundGeom)) { - chtorem = new OdeCharacter[_characters.Count]; - _characters.CopyTo(chtorem); - } + RegionTerrain.Remove(m_worldOffset); + if (GroundGeom != IntPtr.Zero) + { + if (TerrainHeightFieldHeights.ContainsKey(GroundGeom)) + TerrainHeightFieldHeights.Remove(GroundGeom); + d.GeomDestroy(GroundGeom); + } + } - ChangesQueue.Clear(); - foreach (OdeCharacter ch in chtorem) - ch.DoAChange(changes.Remove, null); - - if (TerrainGeom != IntPtr.Zero) - d.GeomDestroy(TerrainGeom); - TerrainGeom = IntPtr.Zero; - - if (TerrainHeightFieldHeightsHandler.IsAllocated) - TerrainHeightFieldHeightsHandler.Free(); - - TerrainHeightFieldHeight = null; - - if (ContactgeomsArray != IntPtr.Zero) + try { - Marshal.FreeHGlobal(ContactgeomsArray); - ContactgeomsArray = IntPtr.Zero; + d.WorldDestroy(world); + world = IntPtr.Zero; } - if (GlobalContactsArray != IntPtr.Zero) + catch (AccessViolationException e) { - Marshal.FreeHGlobal(GlobalContactsArray); - GlobalContactsArray = IntPtr.Zero; + m_log.ErrorFormat("[ODE SCENE]: exception {0}", e.Message); } - - d.WorldDestroy(world); - world = IntPtr.Zero; - //d.CloseODE(); } } @@ -2497,13 +3436,17 @@ namespace OpenSim.Region.PhysicsModule.ubOde public override Dictionary GetTopColliders() { Dictionary topColliders; - List orderedPrims; - lock (_activeprims) - orderedPrims = new List(_activeprims); - orderedPrims.Sort(compareByCollisionsDesc); - topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore); - + lock (_prims) + { + List orderedPrims = new List(_prims); + orderedPrims.Sort(compareByCollisionsDesc); + topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore); + + foreach (OdePrim p in _prims) + p.CollisionScore = 0; + } + return topColliders; } @@ -2516,16 +3459,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde { if (retMethod != null) { - ODERayRequest req = new ODERayRequest(); - req.actor = null; - req.callbackMethod = retMethod; - req.length = length; - req.Normal = direction; - req.Origin = position; - req.Count = 0; - req.filter = RayFilterFlags.AllPrims; - - m_rayCastManager.QueueRequest(req); + m_rayCastManager.QueueRequest(position, direction, length, retMethod); } } @@ -2533,260 +3467,75 @@ namespace OpenSim.Region.PhysicsModule.ubOde { if (retMethod != null) { - ODERayRequest req = new ODERayRequest(); - req.actor = null; - req.callbackMethod = retMethod; - req.length = length; - req.Normal = direction; - req.Origin = position; - req.Count = Count; - req.filter = RayFilterFlags.AllPrims; - - m_rayCastManager.QueueRequest(req); + m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); } } - public override List RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) { - List ourresults = new List(); - object SyncObject = new object(); - + ContactResult[] ourResults = null; RayCallback retMethod = delegate(List results) { - lock (SyncObject) - { - ourresults = results; - Monitor.PulseAll(SyncObject); - } + ourResults = new ContactResult[results.Count]; + results.CopyTo(ourResults, 0); }; - - ODERayRequest req = new ODERayRequest(); - req.actor = null; - req.callbackMethod = retMethod; - req.length = length; - req.Normal = direction; - req.Origin = position; - req.Count = Count; - req.filter = RayFilterFlags.AllPrims; - - lock (SyncObject) + int waitTime = 0; + m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); + while (ourResults == null && waitTime < 1000) { - m_rayCastManager.QueueRequest(req); - if (!Monitor.Wait(SyncObject, 500)) - return null; - else - return ourresults; + Thread.Sleep(1); + waitTime++; } - } - - public override bool SupportsRaycastWorldFiltered() - { - return true; - } - - public override object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter) - { - object SyncObject = new object(); - List ourresults = new List(); - - RayCallback retMethod = delegate(List results) - { - lock (SyncObject) - { - ourresults = results; - Monitor.PulseAll(SyncObject); - } - }; - - ODERayRequest req = new ODERayRequest(); - req.actor = null; - req.callbackMethod = retMethod; - req.length = length; - req.Normal = direction; - req.Origin = position; - req.Count = Count; - req.filter = filter; - - lock (SyncObject) - { - m_rayCastManager.QueueRequest(req); - if (!Monitor.Wait(SyncObject, 500)) - return null; - else - return ourresults; - } - } - - public override List RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags flags) - { - if (actor == null) - return new List(); - - IntPtr geom; - if (actor is OdePrim) - geom = ((OdePrim)actor).prim_geom; - else if (actor is OdeCharacter) - geom = ((OdePrim)actor).prim_geom; - else - return new List(); - - if (geom == IntPtr.Zero) - return new List(); - - List ourResults = null; - object SyncObject = new object(); - - RayCallback retMethod = delegate(List results) - { - lock (SyncObject) - { - ourResults = results; - Monitor.PulseAll(SyncObject); - } - }; - - ODERayRequest req = new ODERayRequest(); - req.actor = actor; - req.callbackMethod = retMethod; - req.length = length; - req.Normal = direction; - req.Origin = position; - req.Count = Count; - req.filter = flags; - - lock (SyncObject) - { - m_rayCastManager.QueueRequest(req); - if (!Monitor.Wait(SyncObject, 500)) - return new List(); - } - if (ourResults == null) - return new List(); - return ourResults; + return new List (); + return new List(ourResults); } - public override List BoxProbe(Vector3 position, Vector3 size, Quaternion orientation, int Count, RayFilterFlags flags) + public override Dictionary GetStats() { - List ourResults = null; - object SyncObject = new object(); + if (!CollectStats) + return null; - ProbeBoxCallback retMethod = delegate(List results) + Dictionary returnStats; + + lock (OdeLock) { - lock (SyncObject) - { - ourResults = results; - Monitor.PulseAll(SyncObject); - } - }; + returnStats = new Dictionary(m_stats); - ODERayRequest req = new ODERayRequest(); - req.actor = null; - req.callbackMethod = retMethod; - req.Normal = size; - req.Origin = position; - req.orientation = orientation; - req.Count = Count; - req.filter = flags; + // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by + // 3 from the SimStatsReporter. + returnStats[ODETotalAvatarsStatName] = _characters.Count * 3; + returnStats[ODETotalPrimsStatName] = _prims.Count * 3; + returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3; - lock (SyncObject) - { - m_rayCastManager.QueueRequest(req); - if (!Monitor.Wait(SyncObject, 500)) - return new List(); + InitializeExtraStats(); } - if (ourResults == null) - return new List(); - return ourResults; + returnStats[ODEOtherCollisionFrameMsStatName] + = returnStats[ODEOtherCollisionFrameMsStatName] + - returnStats[ODENativeSpaceCollisionFrameMsStatName] + - returnStats[ODENativeGeomCollisionFrameMsStatName]; + + return returnStats; } - public override List SphereProbe(Vector3 position, float radius, int Count, RayFilterFlags flags) + private void InitializeExtraStats() { - List ourResults = null; - object SyncObject = new object(); - - ProbeSphereCallback retMethod = delegate(List results) - { - ourResults = results; - Monitor.PulseAll(SyncObject); - }; - - ODERayRequest req = new ODERayRequest(); - req.actor = null; - req.callbackMethod = retMethod; - req.length = radius; - req.Origin = position; - req.Count = Count; - req.filter = flags; - - - lock (SyncObject) - { - m_rayCastManager.QueueRequest(req); - if (!Monitor.Wait(SyncObject, 500)) - return new List(); - } - - if (ourResults == null) - return new List(); - return ourResults; + m_stats[ODETotalFrameMsStatName] = 0; + m_stats[ODEAvatarTaintMsStatName] = 0; + m_stats[ODEPrimTaintMsStatName] = 0; + m_stats[ODEAvatarForcesFrameMsStatName] = 0; + m_stats[ODEPrimForcesFrameMsStatName] = 0; + m_stats[ODERaycastingFrameMsStatName] = 0; + m_stats[ODENativeStepFrameMsStatName] = 0; + m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0; + m_stats[ODENativeGeomCollisionFrameMsStatName] = 0; + m_stats[ODEOtherCollisionFrameMsStatName] = 0; + m_stats[ODECollisionNotificationFrameMsStatName] = 0; + m_stats[ODEAvatarContactsStatsName] = 0; + m_stats[ODEPrimContactsStatName] = 0; + m_stats[ODEAvatarUpdateFrameMsStatName] = 0; + m_stats[ODEPrimUpdateFrameMsStatName] = 0; } - - public override List PlaneProbe(PhysicsActor actor, Vector4 plane, int Count, RayFilterFlags flags) - { - IntPtr geom = IntPtr.Zero;; - - if (actor != null) - { - if (actor is OdePrim) - geom = ((OdePrim)actor).prim_geom; - else if (actor is OdeCharacter) - geom = ((OdePrim)actor).prim_geom; - } - - List ourResults = null; - object SyncObject = new object(); - - ProbePlaneCallback retMethod = delegate(List results) - { - ourResults = results; - Monitor.PulseAll(SyncObject); - }; - - ODERayRequest req = new ODERayRequest(); - req.actor = null; - req.callbackMethod = retMethod; - req.length = plane.W; - req.Normal.X = plane.X; - req.Normal.Y = plane.Y; - req.Normal.Z = plane.Z; - req.Count = Count; - req.filter = flags; - - lock (SyncObject) - { - m_rayCastManager.QueueRequest(req); - if (!Monitor.Wait(SyncObject, 500)) - return new List(); - } - - if (ourResults == null) - return new List(); - return ourResults; - } - - public override int SitAvatar(PhysicsActor actor, Vector3 AbsolutePosition, Vector3 CameraPosition, Vector3 offset, Vector3 AvatarSize, SitAvatarCallback PhysicsSitResponse) - { - Util.FireAndForget( delegate - { - ODESitAvatar sitAvatar = new ODESitAvatar(this, m_rayCastManager); - if(sitAvatar != null) - sitAvatar.Sit(actor, AbsolutePosition, CameraPosition, offset, AvatarSize, PhysicsSitResponse); - }); - return 1; - } - } } diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs b/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs index f6426998d3..410463c77a 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODEScene.cs @@ -2267,8 +2267,6 @@ namespace OpenSim.Region.PhysicsModule.ubOde IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); - GC.Collect(1); - TerrainHeightFieldHeightsHandler = GCHandle.Alloc(_heightmap, GCHandleType.Pinned); d.GeomHeightfieldDataBuildSingle(HeightmapData, TerrainHeightFieldHeightsHandler.AddrOfPinnedObject(), 0, From f510898188e7ba54460858a9c934e898b15de2ce Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Fri, 30 Dec 2016 14:33:15 +0000 Subject: [PATCH 233/305] Fake accepting materials (Type == -2) on FSAssets. Materials are created with an MD5 hash based UUID in order to stop proliferation of orphaned assets. Therefore a UUID collision is expected on materials and should not have been treated as an error. --- OpenSim/Services/FSAssetService/FSAssetService.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Services/FSAssetService/FSAssetService.cs b/OpenSim/Services/FSAssetService/FSAssetService.cs index 7f1446272e..cddd288c89 100644 --- a/OpenSim/Services/FSAssetService/FSAssetService.cs +++ b/OpenSim/Services/FSAssetService/FSAssetService.cs @@ -668,6 +668,9 @@ namespace OpenSim.Services.FSAssetService if (!m_DataConnector.Store(asset.Metadata, hash)) { + if (asset.Metadata.Type == -2) + return asset.ID; + return UUID.Zero.ToString(); } else From da08e2e5f5be597919b4844675af944e4461711f Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 30 Dec 2016 19:12:56 +0000 Subject: [PATCH 234/305] mantis 8106: improve avatar walk in mouselook --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 5082b9d654..f906d9fed0 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3674,12 +3674,18 @@ namespace OpenSim.Region.Framework.Scenes // vec, Rotation, thisAddSpeedModifier, Name); // rotate from avatar coord space to world - // for now all controls assume this is only a rotation around Z - // if not all checks below need to be done before this rotation - Vector3 direc = vec * Rotation; + Quaternion rot = Rotation; + if (!Flying && PresenceType != PresenceType.Npc) + { + // force rotation to be around Z only, if not flying + // needed for mouselook + rot.X = 0; + rot.Y = 0; + } + + Vector3 direc = vec * rot; direc.Normalize(); - // mouse look situation ? if ((vec.Z == 0f) && !Flying) direc.Z = 0f; // Prevent camera WASD up. From 7abb0477ed740663934fa908b282eb51055bc132 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 31 Dec 2016 08:58:06 -0800 Subject: [PATCH 235/305] Replaced OpenMetaverse libs/xmls with new ones. Also added a file in openmetaverse_data that was added recently to libomv and was missing. --- bin/OpenMetaverse.Rendering.Meshmerizer.dll | Bin 20480 -> 20480 bytes bin/OpenMetaverse.StructuredData.dll | Bin 102400 -> 102400 bytes bin/OpenMetaverse.XML | 29284 +++++++++--------- bin/OpenMetaverse.dll | Bin 2195456 -> 2199552 bytes bin/OpenMetaverseTypes.XML | 319 +- bin/OpenMetaverseTypes.dll | Bin 110592 -> 110592 bytes bin/openmetaverse_data/avatar_skeleton.xml | 81 + 7 files changed, 15123 insertions(+), 14561 deletions(-) create mode 100644 bin/openmetaverse_data/avatar_skeleton.xml diff --git a/bin/OpenMetaverse.Rendering.Meshmerizer.dll b/bin/OpenMetaverse.Rendering.Meshmerizer.dll index cca8f3fb6c3c715b4f874e55b8fb5fcab44a41c7..1a12a1e7744044d2136d7fd19b935420e472e622 100755 GIT binary patch delta 47 zcmV+~0MP${paFoO0g#9U{NZOY)6z>24 diff --git a/bin/OpenMetaverse.StructuredData.dll b/bin/OpenMetaverse.StructuredData.dll index 41dd0cc458bc1a295dea8e45cacffcf9a13b4fc5..7aeb0894f2a071c91f3af89d305e43e2587632a4 100755 GIT binary patch delta 1334 zcmYk+e@v8h90%~v`?-e`f#bOQ9=`C_+#Kcft&V9ipd#U=gDhOq*L`9q|XDEt~(8tF7;I&ll%y_u2RL`Fx(w z=X>|Z#hN_bk?5ZiYtmdbrN)u*2E zZN%H^U%p~{fu!VXv!75T#Th%~)XZ9`+Bjpf8k9DY1urgwYeao=W_R9l}n}Nu9S7M%ZCgwrM&}KO~JaKbnQkaW$b^Xq#i4 z9fAFn-nrd1#g4++uFIY|%Ra>cp^-H=Su-L+A+8qO7h24G-Esn^4v+reV&)y|Nv!Hv z*7KG&6h6>AJB58hm-B90+HqKDCiQzu2d0G_`Ah6GyxXNuxt@8Cb)ocgO##ZtpJ!j7 zyH{7A{a@CN?jXGsD;{#i*}jA`q!+IzCEI$iTgbd}*4&E$p-pR2ZN11o9qY_!QD)5{ z^v9&q!SvO(5Ej&J-(`93#&Y%4Mq&9h41HREJ=GvA_ajYcObW|quukZALs%ZbvqHUc zSpFI>3YEl#ygrZ#Maoi&~K@N%_DAWcAUBr2zCCNdTFfC-2 z9dsGDgnr~2#a*FYaSj@T)UW@DIj$?P3GFdDXdI6VC9H7J1d94M>#ePvS5YR4dHgcp zpi-!aU*=oX3jIMB%##naOP3m&%38f&bfoeBZW6COrcFMW5m1aYg{Hyi)H^xP-QX{x zpJ|cDn^f^WXpY|E@fPjl@fT{~@mFf)F-k!m=V^e)-)NM_1)3cEWa(;EO2mCJdFVgi zrn5b+y<>8uV0dRaoT;Xuc*SW;ue7vRAqzvpBUN~LrMdwr!^zdSZB@V-!&KOB%*gj0bx~SR2 zmcll&(2eeH@-}d|33MaVSyGBa2hu4vYJj-RD5x+#AoC?=elTV+-uAf?e3G8r-#O== zd;5HNTxX50v&PnDedZR!E^o_SSn&FGp_KzpEcqMYOtyqx14W*#;-@161^t#ach^GU z4>;$Nw#N`ue>M0**}b`>F+SGtOlW_3jAGC##nhpDxm09bIpT zuB&)r!#2e8ryIUBJuJ@CDJ3G$;`n8EDld0eth*68J$s!}D$+_>^t@0smAg81nO}03 z;}!mgyQK6%onnj3zITI8DU2@i9WyCZXPiz-iTNkJiU_qki4q(tqdMhfP{OO(V(!7% z0)KU5C=Rhazh$u?*Ks(5>daWZq0IWf4RO&i1>EMTwA#g;wh>tzyG75cUHqg+F|fiI zvh#6Idi=^X{+;I;|Hk9?66XOfwvw0TbL-hb+>yF%t!IZYa7wF<7T2>kVLGkpo1A)9 zk1?suwifml>}^`DxA+uup-JjWPB(MI-mcY>68l&aLLHj!Pkf&p#f#2Pjkgj;*fCUh zMf5g(ZJJ;nbVvn-j$=UT33Y;Hvo03!ea6rl&KV$C4 znAGF>X{r5CFGM@7ZOV+cgM>p)azWbTQJ=NL>`rUjUPGAfO+_JyPSk zfc_F5mHIg*p#K2drTX;&{fBr#s?-qB55XZdBox45sV&BUK8SXyd7+Qc=adYQN}~u$ zbwQ<%5tdrksq_hErBd`NUBz!wQ$k~)LG4fMF{m_-6sb9(Pmw28YgB0ho1_wARSIG2 zV1>4^UGN%q%i?-*na{9a$}TSRIU1#Yr7Pyi746Z)JHlCOkI9a7@$M$^TwY}I5vx}* zQW!n{>F`V0k1UB#)%Wz5h_kfsbt3zEaH#UF5*u#AmTg)MO>gU5pU9zh>P^C z|IqTanl*!aT{p|0U4C+;!nJqm#=e~49hE3dOA5-5VC2x5Hct(*5E}N?U}yYravlCQ Q>lQZ+TU_|v>@AG_7X?*c{Qv*} diff --git a/bin/OpenMetaverse.XML b/bin/OpenMetaverse.XML index 36e5b9272b..ce8ca8678a 100644 --- a/bin/OpenMetaverse.XML +++ b/bin/OpenMetaverse.XML @@ -218,6 +218,9 @@ Event message when an object uses llOwnerSay + + Event message when an object uses llRegionSayTo + Special value to support llRegionSay, never sent to the client @@ -880,6 +883,13 @@ Manager class for our own avatar + + + Called once attachment resource usage information has been collected + + Indicates if operation was successfull + Attachment resource usage information + The event subscribers. null if no subcribers @@ -891,6 +901,9 @@ Thread sync lock object + + Raised when a scripted object or agent within range sends a public message + The event subscribers. null if no subcribers @@ -902,6 +915,10 @@ Thread sync lock object + + Raised when a scripted object sends a dialog box containing possible + options an agent can respond to + The event subscribers. null if no subcribers @@ -913,6 +930,9 @@ Thread sync lock object + + Raised when an object requests a change in the permissions an agent has permitted + The event subscribers. null if no subcribers @@ -924,6 +944,9 @@ Thread sync lock object + + Raised when a script requests an agent open the specified URL + The event subscribers. null if no subcribers @@ -935,6 +958,9 @@ Thread sync lock object + + Raised when an agents currency balance is updated + The event subscribers. null if no subcribers @@ -946,6 +972,9 @@ Thread sync lock object + + Raised when a transaction occurs involving currency such as a land purchase + The event subscribers. null if no subcribers @@ -957,6 +986,10 @@ Thread sync lock object + + Raised when an ImprovedInstantMessage packet is recieved from the simulator, this is used for everything from + private messaging to friendship offers. The Dialog field defines what type of message has arrived + The event subscribers. null if no subcribers @@ -968,6 +1001,10 @@ Thread sync lock object + + Raised when an agent has requested a teleport to another location, or when responding to a lure. Raised multiple times + for each teleport indicating the progress of the request + The event subscribers. null if no subcribers @@ -979,6 +1016,9 @@ Thread sync lock object + + Raised when a simulator sends agent specific information for our avatar. + The event subscribers. null if no subcribers @@ -990,6 +1030,9 @@ Thread sync lock object + + Raised when our agents animation playlist changes + The event subscribers. null if no subcribers @@ -1001,6 +1044,9 @@ Thread sync lock object + + Raised when an object or avatar forcefully collides with our agent + The event subscribers. null if no subcribers @@ -1012,6 +1058,9 @@ Thread sync lock object + + Raised when our agent crosses a region border into another region + The event subscribers. null if no subcribers @@ -1023,6 +1072,9 @@ Thread sync lock object + + Raised when our agent succeeds or fails to join a group chat session + The event subscribers. null if no subcribers @@ -1034,6 +1086,10 @@ Thread sync lock object + + Raised when a simulator sends an urgent message usually indication the recent failure of + another action we have attempted to take such as an attempt to enter a parcel where we are denied access + The event subscribers. null if no subcribers @@ -1045,6 +1101,9 @@ Thread sync lock object + + Raised when a script attempts to take or release specified controls for our agent + The event subscribers. null if no subcribers @@ -1056,6 +1115,10 @@ Thread sync lock object + + Raised when the simulator detects our agent is trying to view something + beyond its limits + The event subscribers. null if no subcribers @@ -1067,6 +1130,9 @@ Thread sync lock object + + Raised when a script sensor reply is received from a simulator + The event subscribers. null if no subcribers @@ -1078,6 +1144,9 @@ Thread sync lock object + + Raised in response to a request + The event subscribers. null if no subcribers @@ -1089,6 +1158,9 @@ Thread sync lock object + + Raised when an avatar enters a group chat session we are participating in + The event subscribers. null if no subcribers @@ -1100,6 +1172,9 @@ Thread sync lock object + + Raised when an agent exits a group chat session we are participating in + The event subscribers, null of no subscribers @@ -1111,6 +1186,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + the details of display name change + The event subscribers. null if no subcribers @@ -1122,6 +1201,9 @@ Thread sync lock object + + Raised when a scripted object or agent within range sends a public message + Reference to the GridClient instance @@ -1139,6 +1221,96 @@ Dictionary containing mute list keyead on mute name and key + + Your (client) avatars + "client", "agent", and "avatar" all represent the same thing + + + Temporary assigned to this session, used for + verifying our identity in packets + + + Shared secret that is never sent over the wire + + + Your (client) avatar ID, local to the current region/sim + + + Where the avatar started at login. Can be "last", "home" + or a login + + + The access level of this agent, usually M, PG or A + + + The CollisionPlane of Agent + + + An representing the velocity of our agent + + + An representing the acceleration of our agent + + + A which specifies the angular speed, and axis about which an Avatar is rotating. + + + Position avatar client will goto when login to 'home' or during + teleport request to 'home' region. + + + LookAt point saved/restored with HomePosition + + + Avatar First Name (i.e. Philip) + + + Avatar Last Name (i.e. Linden) + + + LookAt point received with the login response message + + + Avatar Full Name (i.e. Philip Linden) + + + Gets the health of the agent + + + Gets the current balance of the agent + + + Gets the local ID of the prim the agent is sitting on, + zero if the avatar is not currently sitting + + + Gets the of the agents active group. + + + Gets the Agents powers in the currently active group + + + Current status message for teleporting + + + Current position of the agent as a relative offset from + the simulator, or the parent object if we are sitting on something + + + Current rotation of the agent as a relative rotation from + the simulator, or the parent object if we are sitting on something + + + Current position of the agent in the simulator + + + + A representing the agents current rotation + + + + Returns the global grid position of the avatar + Various abilities and preferences sent by the grid @@ -1251,7 +1423,7 @@ Start a friends conference List of UUIDs to start a conference with - the temportary session ID returned in the callback> + the temportary session ID returned in the callback> @@ -2000,175 +2172,6 @@ The sender The EventArgs object containing the packet data - - Raised when a scripted object or agent within range sends a public message - - - Raised when a scripted object sends a dialog box containing possible - options an agent can respond to - - - Raised when an object requests a change in the permissions an agent has permitted - - - Raised when a script requests an agent open the specified URL - - - Raised when an agents currency balance is updated - - - Raised when a transaction occurs involving currency such as a land purchase - - - Raised when an ImprovedInstantMessage packet is recieved from the simulator, this is used for everything from - private messaging to friendship offers. The Dialog field defines what type of message has arrived - - - Raised when an agent has requested a teleport to another location, or when responding to a lure. Raised multiple times - for each teleport indicating the progress of the request - - - Raised when a simulator sends agent specific information for our avatar. - - - Raised when our agents animation playlist changes - - - Raised when an object or avatar forcefully collides with our agent - - - Raised when our agent crosses a region border into another region - - - Raised when our agent succeeds or fails to join a group chat session - - - Raised when a simulator sends an urgent message usually indication the recent failure of - another action we have attempted to take such as an attempt to enter a parcel where we are denied access - - - Raised when a script attempts to take or release specified controls for our agent - - - Raised when the simulator detects our agent is trying to view something - beyond its limits - - - Raised when a script sensor reply is received from a simulator - - - Raised in response to a request - - - Raised when an avatar enters a group chat session we are participating in - - - Raised when an agent exits a group chat session we are participating in - - - Raised when the simulator sends us data containing - the details of display name change - - - Raised when a scripted object or agent within range sends a public message - - - Your (client) avatars - "client", "agent", and "avatar" all represent the same thing - - - Temporary assigned to this session, used for - verifying our identity in packets - - - Shared secret that is never sent over the wire - - - Your (client) avatar ID, local to the current region/sim - - - Where the avatar started at login. Can be "last", "home" - or a login - - - The access level of this agent, usually M, PG or A - - - The CollisionPlane of Agent - - - An representing the velocity of our agent - - - An representing the acceleration of our agent - - - A which specifies the angular speed, and axis about which an Avatar is rotating. - - - Position avatar client will goto when login to 'home' or during - teleport request to 'home' region. - - - LookAt point saved/restored with HomePosition - - - Avatar First Name (i.e. Philip) - - - Avatar Last Name (i.e. Linden) - - - LookAt point received with the login response message - - - Avatar Full Name (i.e. Philip Linden) - - - Gets the health of the agent - - - Gets the current balance of the agent - - - Gets the local ID of the prim the agent is sitting on, - zero if the avatar is not currently sitting - - - Gets the of the agents active group. - - - Gets the Agents powers in the currently active group - - - Current status message for teleporting - - - Current position of the agent as a relative offset from - the simulator, or the parent object if we are sitting on something - - - Current rotation of the agent as a relative rotation from - the simulator, or the parent object if we are sitting on something - - - Current position of the agent in the simulator - - - - A representing the agents current rotation - - - - Returns the global grid position of the avatar - - - - Called once attachment resource usage information has been collected - - Indicates if operation was successfull - Attachment resource usage information - Agent movement and camera control @@ -2183,119 +2186,36 @@ The Z axis is Up, finer grained control of movements can be done using the Nudge properties - - Agent camera controls - - - Currently only used for hiding your group title - - - Action state of the avatar, which can currently be - typing and editing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Timer for sending AgentUpdate packets - - - Default constructor - - + - Send an AgentUpdate with the camera set at the current agent - position and pointing towards the heading specified - - Camera rotation in radians - Whether to send the AgentUpdate reliable - or not - - - - Rotates the avatar body and camera toward a target position. - This will also anchor the camera position on the avatar - - Region coordinates to turn toward - - - - Rotates the avatar body and camera toward a target position. - This will also anchor the camera position on the avatar - - Region coordinates to turn toward - whether to send update or not - - - - Send new AgentUpdate packet to update our current camera - position and rotation + Camera controls for the agent, mostly a thin wrapper around + CoordinateFrame. This class is only responsible for state + tracking and math, it does not send any packets - - - Send new AgentUpdate packet to update our current camera - position and rotation - - Whether to require server acknowledgement - of this packet + + - - - Send new AgentUpdate packet to update our current camera - position and rotation - - Whether to require server acknowledgement - of this packet - Simulator to send the update to + + The camera is a local frame of reference inside of + the larger grid space. This is where the math happens - - - Builds an AgentUpdate packet entirely from parameters. This - will not touch the state of Self.Movement or - Self.Movement.Camera in any way - - - - - - - - - - - - + + - + + + + + + + + + + - Sends update of Field of Vision vertical angle to the simulator + Default constructor - Angle in radians Move agent positive along the X axis @@ -2414,36 +2334,119 @@ Reset movement controls every time we send an update - + + Agent camera controls + + + Currently only used for hiding your group title + + + Action state of the avatar, which can currently be + typing and editing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Timer for sending AgentUpdate packets + + + Default constructor + + - Camera controls for the agent, mostly a thin wrapper around - CoordinateFrame. This class is only responsible for state - tracking and math, it does not send any packets + Send an AgentUpdate with the camera set at the current agent + position and pointing towards the heading specified + + Camera rotation in radians + Whether to send the AgentUpdate reliable + or not + + + + Rotates the avatar body and camera toward a target position. + This will also anchor the camera position on the avatar + + Region coordinates to turn toward + + + + Rotates the avatar body and camera toward a target position. + This will also anchor the camera position on the avatar + + Region coordinates to turn toward + whether to send update or not + + + + Send new AgentUpdate packet to update our current camera + position and rotation - - - - - The camera is a local frame of reference inside of - the larger grid space. This is where the math happens - - + - Default constructor + Send new AgentUpdate packet to update our current camera + position and rotation + Whether to require server acknowledgement + of this packet - - + + + Send new AgentUpdate packet to update our current camera + position and rotation + + Whether to require server acknowledgement + of this packet + Simulator to send the update to - - + + + Builds an AgentUpdate packet entirely from parameters. This + will not touch the state of Self.Movement or + Self.Movement.Camera in any way + + + + + + + + + + + + - - - - - + + + Sends update of Field of Vision vertical angle to the simulator + + Angle in radians @@ -2556,13 +2559,6 @@ of setting the maturity access level - - - Creates new instance of the EventArgs class - - Has setting new maturty access level succeeded - New maturity access level as returned by the simulator - New maturity accesss level returned from the sim @@ -2573,25 +2569,18 @@ True if setting the new maturity access level has succedded + + + Creates new instance of the EventArgs class + + Has setting new maturty access level succeeded + New maturity access level as returned by the simulator + - - - Construct a new instance of the ChatEventArgs object - - Sim from which the message originates - The message sent - The audible level of the message - The type of message sent: whisper, shout, etc - The source type of the message sender - The name of the agent or object sending the message - The ID of the agent or object sending the message - The ID of the object owner, or the agent ID sending the message - The position of the agent or object sending the message - Get the simulator sending the message @@ -2619,23 +2608,23 @@ Get the position of the agent or object sending the message + + + Construct a new instance of the ChatEventArgs object + + Sim from which the message originates + The message sent + The audible level of the message + The type of message sent: whisper, shout, etc + The source type of the message sender + The name of the agent or object sending the message + The ID of the agent or object sending the message + The ID of the object owner, or the agent ID sending the message + The position of the agent or object sending the message + Contains the data sent when a primitive opens a dialog with this agent - - - Construct a new instance of the ScriptDialogEventArgs - - The dialog message - The name of the object that sent the dialog request - The ID of the image to be displayed - The ID of the primitive sending the dialog - The first name of the senders owner - The last name of the senders owner - The communication channel the dialog was sent on - The string labels containing the options presented in this dialog - UUID of the scritped object owner - Get the dialog message @@ -2664,21 +2653,24 @@ UUID of the scritped object owner + + + Construct a new instance of the ScriptDialogEventArgs + + The dialog message + The name of the object that sent the dialog request + The ID of the image to be displayed + The ID of the primitive sending the dialog + The first name of the senders owner + The last name of the senders owner + The communication channel the dialog was sent on + The string labels containing the options presented in this dialog + UUID of the scritped object owner + Contains the data sent when a primitive requests debit or other permissions requesting a YES or NO answer - - - Construct a new instance of the ScriptQuestionEventArgs - - The simulator containing the object sending the request - The ID of the script making the request - The ID of the primitive containing the script making the request - The name of the primitive making the request - The name of the owner of the object making the request - The permissions being requested - Get the simulator containing the object sending the request @@ -2697,21 +2689,21 @@ Get the permissions being requested + + + Construct a new instance of the ScriptQuestionEventArgs + + The simulator containing the object sending the request + The ID of the script making the request + The ID of the primitive containing the script making the request + The name of the primitive making the request + The name of the owner of the object making the request + The permissions being requested + Contains the data sent when a primitive sends a request to an agent to open the specified URL - - - Construct a new instance of the LoadUrlEventArgs - - The name of the object sending the request - The ID of the object sending the request - The ID of the owner of the object sending the request - True if the object is owned by a group - The message sent with the request - The URL the object sent - Get the name of the object sending the request @@ -2730,9 +2722,26 @@ Get the URL the object sent + + + Construct a new instance of the LoadUrlEventArgs + + The name of the object sending the request + The ID of the object sending the request + The ID of the owner of the object sending the request + True if the object is owned by a group + The message sent with the request + The URL the object sent + The date received from an ImprovedInstantMessage + + Get the InstantMessage object + + + Get the simulator where the InstantMessage origniated + Construct a new instance of the InstantMessageEventArgs object @@ -2740,42 +2749,24 @@ the InstantMessage object the simulator where the InstantMessage origniated - - Get the InstantMessage object - - - Get the simulator where the InstantMessage origniated - Contains the currency balance + + + Get the currenct balance + + Construct a new BalanceEventArgs object The currenct balance - - - Get the currenct balance - - Contains the transaction summary when an item is purchased, money is given, or land is purchased - - - Construct a new instance of the MoneyBalanceReplyEventArgs object - - The ID of the transaction - True of the transaction was successful - The current currency balance - The meters credited - The meters comitted - A brief description of the transaction - Transaction info - Get the ID of the transaction @@ -2797,20 +2788,21 @@ Detailed transaction information + + + Construct a new instance of the MoneyBalanceReplyEventArgs object + + The ID of the transaction + True of the transaction was successful + The current currency balance + The meters credited + The meters comitted + A brief description of the transaction + Transaction info + Data sent from the simulator containing information about your agent and active group information - - - Construct a new instance of the AgentDataReplyEventArgs object - - The agents first name - The agents last name - The agents active group ID - The group title of the agents active group - The combined group powers the agent has in the active group - The name of the group the agent has currently active - Get the agents first name @@ -2829,34 +2821,35 @@ Get the active group name of your agent + + + Construct a new instance of the AgentDataReplyEventArgs object + + The agents first name + The agents last name + The agents active group ID + The group title of the agents active group + The combined group powers the agent has in the active group + The name of the group the agent has currently active + Data sent by the simulator to indicate the active/changed animations applied to your agent + + Get the dictionary that contains the changed animations + Construct a new instance of the AnimationsChangedEventArgs class The dictionary that contains the changed animations - - Get the dictionary that contains the changed animations - Data sent from a simulator indicating a collision with your agent - - - Construct a new instance of the MeanCollisionEventArgs class - - The type of collision that occurred - The ID of the agent or object that perpetrated the agression - The ID of the Victim - The strength of the collision - The Time the collision occurred - Get the Type of collision @@ -2872,9 +2865,25 @@ Get the time the collision occurred + + + Construct a new instance of the MeanCollisionEventArgs class + + The type of collision that occurred + The ID of the agent or object that perpetrated the agression + The ID of the Victim + The strength of the collision + The Time the collision occurred + Data sent to your agent when it crosses region boundaries + + Get the simulator your agent just left + + + Get the simulator your agent is now in + Construct a new instance of the RegionCrossedEventArgs class @@ -2882,24 +2891,9 @@ The simulator your agent just left The simulator your agent is now in - - Get the simulator your agent just left - - - Get the simulator your agent is now in - Data sent from the simulator when your agent joins a group chat session - - - Construct a new instance of the GroupChatJoinedEventArgs class - - The ID of the session - The name of the session - A temporary session id used for establishing new sessions - True of your agent successfully joined the session - Get the ID of the group chat session @@ -2912,29 +2906,30 @@ True if your agent successfully joined the session + + + Construct a new instance of the GroupChatJoinedEventArgs class + + The ID of the session + The name of the session + A temporary session id used for establishing new sessions + True of your agent successfully joined the session + Data sent by the simulator containing urgent messages + + Get the alert message + Construct a new instance of the AlertMessageEventArgs class The alert message - - Get the alert message - Data sent by a script requesting to take or release specified controls to your agent - - - Construct a new instance of the ScriptControlEventArgs class - - The controls the script is attempting to take or release to the agent - True if the script is passing controls back to the agent - True if the script is requesting controls be released to the script - Get the controls the script is attempting to take or release to the agent @@ -2944,41 +2939,34 @@ True if the script is requesting controls be released to the script + + + Construct a new instance of the ScriptControlEventArgs class + + The controls the script is attempting to take or release to the agent + True if the script is passing controls back to the agent + True if the script is requesting controls be released to the script + Data sent from the simulator to an agent to indicate its view limits + + Get the collision plane + Construct a new instance of the CameraConstraintEventArgs class The collision plane - - Get the collision plane - Data containing script sensor requests which allow an agent to know the specific details of a primitive sending script sensor requests - - - Construct a new instance of the ScriptSensorReplyEventArgs - - The ID of the primitive sending the sensor - The ID of the group associated with the primitive - The name of the primitive sending the sensor - The ID of the primitive sending the sensor - The ID of the owner of the primitive sending the sensor - The position of the primitive sending the sensor - The range the primitive specified to scan - The rotation of the primitive sending the sensor - The type of sensor the primitive sent - The velocity of the primitive sending the sensor - Get the ID of the primitive sending the sensor @@ -3009,12 +2997,24 @@ Get the velocity of the primitive sending the sensor + + + Construct a new instance of the ScriptSensorReplyEventArgs + + The ID of the primitive sending the sensor + The ID of the group associated with the primitive + The name of the primitive sending the sensor + The ID of the primitive sending the sensor + The ID of the owner of the primitive sending the sensor + The position of the primitive sending the sensor + The range the primitive specified to scan + The rotation of the primitive sending the sensor + The type of sensor the primitive sent + The velocity of the primitive sending the sensor + Contains the response data returned from the simulator in response to a - - Construct a new instance of the AvatarSitResponseEventArgs object - Get the ID of the primitive the agent will be sitting on @@ -3036,9 +3036,18 @@ Get the rotation of the agent when seated + + Construct a new instance of the AvatarSitResponseEventArgs object + Data sent when an agent joins a chat session your agent is currently participating in + + Get the ID of the chat session + + + Get the ID of the agent that joined + Construct a new instance of the ChatSessionMemberAddedEventArgs object @@ -3046,15 +3055,15 @@ The ID of the chat session The ID of the agent joining - - Get the ID of the chat session - - - Get the ID of the agent that joined - Data sent when an agent exits a chat session your agent is currently participating in + + Get the ID of the chat session + + + Get the ID of the agent that left + Construct a new instance of the ChatSessionMemberLeftEventArgs object @@ -3062,18 +3071,9 @@ The ID of the chat session The ID of the Agent that left - - Get the ID of the chat session - - - Get the ID of the agent that left - Event arguments with the result of setting display name operation - - Default constructor - Status code, 200 indicates settign display name was successful @@ -3083,12 +3083,40 @@ Details of the newly set display name + + Default constructor + Throttles the network traffic for various different traffic types. Access this class through GridClient.Throttle + + Maximum bits per second for resending unacknowledged packets + + + Maximum bits per second for LayerData terrain + + + Maximum bits per second for LayerData wind data + + + Maximum bits per second for LayerData clouds + + + Unknown, includes object data + + + Maximum bits per second for textures + + + Maximum bits per second for downloaded assets + + + Maximum bits per second the entire connection, divided up + between invidiual streams using default multipliers + Default constructor, uses a default high total of 1500 KBps (1536000) @@ -3125,31 +3153,6 @@ Byte array containing all the throttle values - - Maximum bits per second for resending unacknowledged packets - - - Maximum bits per second for LayerData terrain - - - Maximum bits per second for LayerData wind data - - - Maximum bits per second for LayerData clouds - - - Unknown, includes object data - - - Maximum bits per second for textures - - - Maximum bits per second for downloaded assets - - - Maximum bits per second the entire connection, divided up - between invidiual streams using default multipliers - Static pre-defined animations available to all agents @@ -3583,6 +3586,12 @@ Appearance Flags, introdued with server side baking, currently unused + + Mask for multiple attachments + + + Mapping between BakeType and AvatarTextureIndex + Maximum number of concurrent downloads for wearable assets and textures @@ -3617,12 +3626,6 @@ Total number of wearables per bake layer - - Mask for multiple attachments - - - Mapping between BakeType and AvatarTextureIndex - Map of what wearables are included in each bake @@ -3634,6 +3637,54 @@ Default avatar texture, used to detect when a custom texture is not set for a face + + + Contains information about a wearable inventory item + + + + Inventory ItemID of the wearable + + + AssetID of the wearable asset + + + WearableType of the wearable + + + AssetType of the wearable + + + Asset data for the wearable + + + + Data collected from visual params for each wearable + needed for the calculation of the color + + + + + Holds a texture assetID and the data needed to bake this layer into + an outfit texture. Used to keep track of currently worn textures + and baking data + + + + A texture AssetID + + + Asset data for the texture + + + Collection of alpha masks that needs applying + + + Tint that should be applied to the texture + + + Where on avatar does this texture belong + The event subscribers. null if no subcribers @@ -3645,6 +3696,11 @@ Thread sync lock object + + Triggered when an AgentWearablesUpdate packet is received, + telling us what our avatar is currently wearing + request. + The event subscribers. null if no subcribers @@ -3656,6 +3712,12 @@ Thread sync lock object + + Raised when an AgentCachedTextureResponse packet is + received, giving a list of cached bakes that were found on the + simulator + request. + The event subscribers. null if no subcribers @@ -3666,6 +3728,13 @@ Thread sync lock object + + + Raised when appearance data is sent to the simulator, also indicates + the main appearance thread is finished. + + request. + The event subscribers. null if no subcribers @@ -3677,6 +3746,17 @@ Thread sync lock object + + + Triggered when the simulator requests the agent rebake its appearance. + + + + + + Returns true if AppearanceManager is busy and trying to set or change appearance will fail + + Visual parameters last sent to the sim @@ -4085,83 +4165,6 @@ A BakeType A list of texture slots that are inputs for the given bake - - Triggered when an AgentWearablesUpdate packet is received, - telling us what our avatar is currently wearing - request. - - - Raised when an AgentCachedTextureResponse packet is - received, giving a list of cached bakes that were found on the - simulator - request. - - - - Raised when appearance data is sent to the simulator, also indicates - the main appearance thread is finished. - - request. - - - - Triggered when the simulator requests the agent rebake its appearance. - - - - - - Returns true if AppearanceManager is busy and trying to set or change appearance will fail - - - - - Contains information about a wearable inventory item - - - - Inventory ItemID of the wearable - - - AssetID of the wearable asset - - - WearableType of the wearable - - - AssetType of the wearable - - - Asset data for the wearable - - - - Data collected from visual params for each wearable - needed for the calculation of the color - - - - - Holds a texture assetID and the data needed to bake this layer into - an outfit texture. Used to keep track of currently worn textures - and baking data - - - - A texture AssetID - - - Asset data for the texture - - - Collection of alpha masks that needs applying - - - Tint that should be applied to the texture - - - Where on avatar does this texture belong - Contains the Event data returned from the data server from an AgentWearablesRequest @@ -4177,18 +4180,21 @@ Contains the Event data returned from an AppearanceSetRequest + + Indicates whether appearance setting was successful + Triggered when appearance data is sent to the sim and the main appearance thread is done. Indicates whether appearance setting was successful - - Indicates whether appearance setting was successful - Contains the Event data returned from the data server from an RebakeAvatarTextures + + The ID of the Texture Layer to bake + Triggered when the simulator sends a request for this agent to rebake @@ -4196,14 +4202,22 @@ The ID of the Texture Layer to bake - - The ID of the Texture Layer to bake - Class that handles the local asset cache + + + Allows setting weather to periodicale prune the cache if it grows too big + Default is enabled, when caching is enabled + + + + + How long (in ms) between cache checks (default is 5 min.) + + Default constructor @@ -4308,17 +4322,6 @@ Byte size we want to output String with humanly readable file size - - - Allows setting weather to periodicale prune the cache if it grows too big - Default is enabled, when caching is enabled - - - - - How long (in ms) between cache checks (default is 5 min.) - - Helper class for sorting files by their last accessed time @@ -4468,6 +4471,26 @@ Number of milliseconds to wait for a transfer header packet if out of order data was received + + + Callback used for various asset download requests + + Transfer information + Downloaded asset, null on fail + + + + Callback used upon competition of baked texture upload + + Asset UUID of the newly uploaded baked texture + + + + A callback that fires upon the completition of the RequestMesh call + + Was the download successfull + Resulting mesh or null on problems + The event subscribers. null if no subcribers @@ -4479,6 +4502,9 @@ Thread sync lock object + + Raised when the simulator responds sends + The event subscribers. null if no subcribers @@ -4490,6 +4516,9 @@ Thread sync lock object + + Raised during upload completes + The event subscribers. null if no subcribers @@ -4501,6 +4530,9 @@ Thread sync lock object + + Raised during upload with progres update + The event subscribers. null if no subcribers @@ -4512,6 +4544,9 @@ Thread sync lock object + + Fired when the simulator sends an InitiateDownloadPacket, used to download terrain .raw files + The event subscribers. null if no subcribers @@ -4523,6 +4558,9 @@ Thread sync lock object + + Fired when a texture is in the process of being downloaded by the TexturePipeline class + Texture download cache @@ -4831,41 +4869,6 @@ The sender The EventArgs object containing the packet data - - Raised when the simulator responds sends - - - Raised during upload completes - - - Raised during upload with progres update - - - Fired when the simulator sends an InitiateDownloadPacket, used to download terrain .raw files - - - Fired when a texture is in the process of being downloaded by the TexturePipeline class - - - - Callback used for various asset download requests - - Transfer information - Downloaded asset, null on fail - - - - Callback used upon competition of baked texture upload - - Asset UUID of the newly uploaded baked texture - - - - A callback that fires upon the completition of the RequestMesh call - - Was the download successfull - Resulting mesh or null on problems - Xfer data @@ -4897,1001 +4900,6 @@ Represents an avatar (other than your own) - - - Particle system specific enumerators, flags and methods. - - - - - Current version of the media data for the prim - - - - - Array of media entries indexed by face number - - - - - - - - - - - - - - - - - - - - - - - - - Foliage type for this primitive. Only applicable if this - primitive is foliage - - - Unknown - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Identifies the owner if audio or a particle system is - active - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Objects physics engine propertis - - - Extra data about primitive - - - Indicates if prim is attached to an avatar - - - Number of clients referencing this prim - - - - Default constructor - - - - - Packs PathTwist, PathTwistBegin, PathRadiusOffset, and PathSkew - parameters in to signed eight bit values - - Floating point parameter to pack - Signed eight bit value containing the packed parameter - - - - Unpacks PathTwist, PathTwistBegin, PathRadiusOffset, and PathSkew - parameters from signed eight bit integers to floating point values - - Signed eight bit value to unpack - Unpacked floating point value - - - - - - - - - Uses basic heuristics to estimate the primitive shape - - - - Complete structure for the particle system - - - - Particle Flags - There appears to be more data packed in to this area - for many particle systems. It doesn't appear to be flag values - and serialization breaks unless there is a flag for every - possible bit so it is left as an unsigned integer - - - pattern of particles - - - A representing the maximimum age (in seconds) particle will be displayed - Maximum value is 30 seconds - - - A representing the number of seconds, - from when the particle source comes into view, - or the particle system's creation, that the object will emits particles; - after this time period no more particles are emitted - - - A in radians that specifies where particles will not be created - - - A in radians that specifies where particles will be created - - - A representing the number of seconds between burts. - - - A representing the number of meters - around the center of the source where particles will be created. - - - A representing in seconds, the minimum speed between bursts of new particles - being emitted - - - A representing in seconds the maximum speed of new particles being emitted. - - - A representing the maximum number of particles emitted per burst - - - A which represents the velocity (speed) from the source which particles are emitted - - - A which represents the Acceleration from the source which particles are emitted - - - The Key of the texture displayed on the particle - - - The Key of the specified target object or avatar particles will follow - - - Flags of particle from - - - Max Age particle system will emit particles for - - - The the particle has at the beginning of its lifecycle - - - The the particle has at the ending of its lifecycle - - - A that represents the starting X size of the particle - Minimum value is 0, maximum value is 4 - - - A that represents the starting Y size of the particle - Minimum value is 0, maximum value is 4 - - - A that represents the ending X size of the particle - Minimum value is 0, maximum value is 4 - - - A that represents the ending Y size of the particle - Minimum value is 0, maximum value is 4 - - - A that represents the start glow value - Minimum value is 0, maximum value is 1 - - - A that represents the end glow value - Minimum value is 0, maximum value is 1 - - - OpenGL blend function to use at particle source - - - OpenGL blend function to use at particle destination - - - - Can this particle system be packed in a legacy compatible way - - True if the particle system doesn't use new particle system features - - - - Decodes a byte[] array into a ParticleSystem Object - - ParticleSystem object - Start position for BitPacker - - - - Generate byte[] array from particle data - - Byte array - - - - Particle source pattern - - - - None - - - Drop particles from source position with no force - - - "Explode" particles in all directions - - - Particles shoot across a 2D area - - - Particles shoot across a 3D Cone - - - Inverse of AngleCone (shoot particles everywhere except the 3D cone defined - - - - Particle Data Flags - - - - None - - - Interpolate color and alpha from start to end - - - Interpolate scale from start to end - - - Bounce particles off particle sources Z height - - - velocity of particles is dampened toward the simulators wind - - - Particles follow the source - - - Particles point towards the direction of source's velocity - - - Target of the particles - - - Particles are sent in a straight line - - - Particles emit a glow - - - used for point/grab/touch - - - continuous ribbon particle - - - particle data contains glow - - - particle data contains blend functions - - - - Particle Flags Enum - - - - None - - - Acceleration and velocity for particles are - relative to the object rotation - - - Particles use new 'correct' angle parameters - - - - Parameters used to construct a visual representation of a primitive - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Calculdates hash code for prim construction data - - The has - - - Attachment point to an avatar - - - - - - - - - - - - - - - - Information on the flexible properties of a primitive - - - - - - - - - - - - - - - - - - - - - - - Default constructor - - - - - - - - - - - - - - - - - - - - - - - - Information on the light properties of a primitive - - - - - - - - - - - - - - - - - - - - Default constructor - - - - - - - - - - - - - - - - - - - - - - - - Information on the light properties of a primitive as texture map - - - - - - - - - - - Default constructor - - - - - - - - - - - - - - - - - - - - - - - - Information on the sculpt properties of a sculpted primitive - - - - - Default constructor - - - - - - - - - - - - Render inside out (inverts the normals). - - - - - Render an X axis mirror of the sculpty. - - - - - Extended properties to describe an object - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default constructor - - - - - Set the properties that are set in an ObjectPropertiesFamily packet - - that has - been partially filled by an ObjectPropertiesFamily packet - - - - Describes physics attributes of the prim - - - - Primitive's local ID - - - Density (1000 for normal density) - - - Friction - - - Gravity multiplier (1 for normal gravity) - - - Type of physics representation of this primitive in the simulator - - - Restitution - - - - Creates PhysicsProperties from OSD - - OSDMap with incoming data - Deserialized PhysicsProperties object - - - - Serializes PhysicsProperties to OSD - - OSDMap with serialized PhysicsProperties data - - - - Texture animation mode - - - - Disable texture animation - - - Enable texture animation - - - Loop when animating textures - - - Animate in reverse direction - - - Animate forward then reverse - - - Slide texture smoothly instead of frame-stepping - - - Rotate texture instead of using frames - - - Scale texture instead of using frames - - - - A single textured face. Don't instantiate this class yourself, use the - methods in TextureEntry - - - - - Contains the definition for individual faces - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - In the future this will specify whether a webpage is - attached to this face - - - - - - - - - - Represents all of the texturable faces for an object - - Grid objects have infinite faces, with each face - using the properties of the default face unless set otherwise. So if - you have a TextureEntry with a default texture uuid of X, and face 18 - has a texture UUID of Y, every face would be textured with X except for - face 18 that uses Y. In practice however, primitives utilize a maximum - of nine faces - - - - - - - - - - Constructor that takes a default texture UUID - - Texture UUID to use as the default texture - - - - Constructor that takes a TextureEntryFace for the - default face - - Face to use as the default face - - - - Constructor that creates the TextureEntry class from a byte array - - Byte array containing the TextureEntry field - Starting position of the TextureEntry field in - the byte array - Length of the TextureEntry field, in bytes - - - - This will either create a new face if a custom face for the given - index is not defined, or return the custom face for that index if - it already exists - - The index number of the face to create or - retrieve - A TextureEntryFace containing all the properties for that - face - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Controls the texture animation of a particular prim - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Groups that this avatar is a member of - - - Positive and negative ratings - - - Avatar properties including about text, profile URL, image IDs and - publishing settings - - - Avatar interests including spoken languages, skills, and "want to" - choices - - - Movement control flags for avatars. Typically not set or used by - clients. To move your avatar, use Client.Self.Movement instead - - - - Contains the visual parameters describing the deformation of the avatar - - - - - Appearance version. Value greater than 0 indicates using server side baking - - - - - Version of the Current Outfit Folder that the appearance is based on - - - - - Appearance flags. Introduced with server side baking, currently unused. - - - - - List of current avatar animations - - - - - Default constructor - - - - First name - - - Last name - - - Full name - - - Active group - Positive and negative ratings @@ -5990,6 +4998,66 @@ + + Groups that this avatar is a member of + + + Positive and negative ratings + + + Avatar properties including about text, profile URL, image IDs and + publishing settings + + + Avatar interests including spoken languages, skills, and "want to" + choices + + + Movement control flags for avatars. Typically not set or used by + clients. To move your avatar, use Client.Self.Movement instead + + + + Contains the visual parameters describing the deformation of the avatar + + + + + Appearance version. Value greater than 0 indicates using server side baking + + + + + Version of the Current Outfit Folder that the appearance is based on + + + + + Appearance flags. Introduced with server side baking, currently unused. + + + + + List of current avatar animations + + + + First name + + + Last name + + + Full name + + + Active group + + + + Default constructor + + Information about agents display name @@ -6008,6 +5076,9 @@ Last name (legacy) + + Full name (legacy) + Is display name default display name @@ -6030,9 +5101,6 @@ OSD containing agent's display name data - - Full name (legacy) - Holds group information for Avatars such as those you might find in a profile @@ -6096,6 +5164,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + an agents animation playlist + The event subscribers, null of no subscribers @@ -6107,6 +5179,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + the appearance information for an agent + The event subscribers, null of no subscribers @@ -6118,6 +5194,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + agent names/id values + The event subscribers, null of no subscribers @@ -6129,6 +5209,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + the interests listed in an agents profile + The event subscribers, null of no subscribers @@ -6140,6 +5224,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + profile property information for an agent + The event subscribers, null of no subscribers @@ -6151,6 +5239,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + the group membership an agent is a member of + The event subscribers, null of no subscribers @@ -6162,6 +5254,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + name/id pair + The event subscribers, null of no subscribers @@ -6173,6 +5269,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + the objects and effect when an agent is pointing at + The event subscribers, null of no subscribers @@ -6184,6 +5284,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + the objects and effect when an agent is looking at + The event subscribers, null of no subscribers @@ -6195,6 +5299,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + an agents viewer effect information + The event subscribers, null of no subscribers @@ -6206,6 +5314,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + the top picks from an agents profile + The event subscribers, null of no subscribers @@ -6217,6 +5329,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + the Pick details + The event subscribers, null of no subscribers @@ -6228,6 +5344,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + the classified ads an agent has placed + The event subscribers, null of no subscribers @@ -6239,6 +5359,10 @@ Thread sync lock object + + Raised when the simulator sends us data containing + the details of a classified ad + The event subscribers, null of no subscribers @@ -6250,6 +5374,18 @@ Thread sync lock object + + Raised when the simulator sends us data containing + the details of display name change + + + + Callback giving results when fetching display names + + If the request was successful + Array of display names + Array of UUIDs that could not be fetched + Represents other avatars @@ -6401,74 +5537,6 @@ The sender The EventArgs object containing the packet data - - Raised when the simulator sends us data containing - an agents animation playlist - - - Raised when the simulator sends us data containing - the appearance information for an agent - - - Raised when the simulator sends us data containing - agent names/id values - - - Raised when the simulator sends us data containing - the interests listed in an agents profile - - - Raised when the simulator sends us data containing - profile property information for an agent - - - Raised when the simulator sends us data containing - the group membership an agent is a member of - - - Raised when the simulator sends us data containing - name/id pair - - - Raised when the simulator sends us data containing - the objects and effect when an agent is pointing at - - - Raised when the simulator sends us data containing - the objects and effect when an agent is looking at - - - Raised when the simulator sends us data containing - an agents viewer effect information - - - Raised when the simulator sends us data containing - the top picks from an agents profile - - - Raised when the simulator sends us data containing - the Pick details - - - Raised when the simulator sends us data containing - the classified ads an agent has placed - - - Raised when the simulator sends us data containing - the details of a classified ad - - - Raised when the simulator sends us data containing - the details of display name change - - - - Callback giving results when fetching display names - - If the request was successful - Array of display names - Array of UUIDs that could not be fetched - Provides data for the event The event occurs when the simulator sends @@ -6509,6 +5577,12 @@ + + Get the ID of the agent + + + Get the list of animations to start + Construct a new instance of the AvatarAnimationEventArgs class @@ -6516,12 +5590,6 @@ The ID of the agent The list of animations to start - - Get the ID of the agent - - - Get the list of animations to start - Provides data for the event The event occurs when the simulator sends @@ -6541,17 +5609,6 @@ - - - Construct a new instance of the AvatarAppearanceEventArgs class - - The simulator request was from - The ID of the agent - true of the agent is a trial account - The default agent texture - The agents appearance layer textures - The for the agent - Get the Simulator this request is from of the agent @@ -6580,6 +5637,17 @@ Appearance flags, introduced with server side baking, currently unused + + + Construct a new instance of the AvatarAppearanceEventArgs class + + The simulator request was from + The ID of the agent + true of the agent is a trial account + The default agent texture + The agents appearance layer textures + The for the agent + Represents the interests from the profile of an agent @@ -6616,6 +5684,12 @@ + + + + + + Default constructor, initialize the bit packer / bit unpacker @@ -6718,12 +5792,6 @@ 32-bit unsigned integer - - - - - - Reads in a byte array of an Animation Asset created by the SecondLife(tm) client. @@ -6924,9 +5992,25 @@ group messaging + + + Triggered when an event is received via the EventQueueGet + capability + + Event name + Decoded event data + The simulator that generated the event + Reference to the simulator this system is connected to + + Capabilities URI this system was initialized with + + + Whether the capabilities event queue is connected and + listening for incoming events + Default constructor @@ -6949,22 +6033,6 @@ - - Capabilities URI this system was initialized with - - - Whether the capabilities event queue is connected and - listening for incoming events - - - - Triggered when an event is received via the EventQueueGet - capability - - Event name - Decoded event data - The simulator that generated the event - Attempts to convert an LLSD structure to a known Packet type @@ -6974,8557 +6042,13 @@ LLSD to convert to a Packet A Packet on success, otherwise null - + - + A custom decoder callback - Looking direction, must be a normalized vector - Up direction, must be a normalized vector - - - - Align the coordinate frame X and Y axis with a given rotation - around the Z axis in radians - - Absolute rotation around the Z axis in - radians - - - Origin position of this coordinate frame - - - X axis of this coordinate frame, or Forward/At in grid terms - - - Y axis of this coordinate frame, or Left in grid terms - - - Z axis of this coordinate frame, or Up in grid terms - - - - Access to the data server which allows searching for land, events, people, etc - - - - The event subscribers. null if no subcribers - - - Raises the EventInfoReply event - An EventInfoReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the DirEventsReply event - An DirEventsReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the PlacesReply event - A PlacesReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the DirPlacesReply event - A DirPlacesReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the DirClassifiedsReply event - A DirClassifiedsReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the DirGroupsReply event - A DirGroupsReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the DirPeopleReply event - A DirPeopleReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the DirLandReply event - A DirLandReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - - Constructs a new instance of the DirectoryManager class - - An instance of GridClient - - - - Query the data server for a list of classified ads containing the specified string. - Defaults to searching for classified placed in any category, and includes PG, Adult and Mature - results. - - Responses are sent 16 per response packet, there is no way to know how many results a query reply will contain however assuming - the reply packets arrived ordered, a response with less than 16 entries would indicate all results have been received - - The event is raised when a response is received from the simulator - - A string containing a list of keywords to search for - A UUID to correlate the results when the event is raised - - - - Query the data server for a list of classified ads which contain specified keywords (Overload) - - The event is raised when a response is received from the simulator - - A string containing a list of keywords to search for - The category to search - A set of flags which can be ORed to modify query options - such as classified maturity rating. - A UUID to correlate the results when the event is raised - - Search classified ads containing the key words "foo" and "bar" in the "Any" category that are either PG or Mature - - UUID searchID = StartClassifiedSearch("foo bar", ClassifiedCategories.Any, ClassifiedQueryFlags.PG | ClassifiedQueryFlags.Mature); - - - - Responses are sent 16 at a time, there is no way to know how many results a query reply will contain however assuming - the reply packets arrived ordered, a response with less than 16 entries would indicate all results have been received - - - - - Starts search for places (Overloaded) - - The event is raised when a response is received from the simulator - - Search text - Each request is limited to 100 places - being returned. To get the first 100 result entries of a request use 0, - from 100-199 use 1, 200-299 use 2, etc. - A UUID to correlate the results when the event is raised - - - - Queries the dataserver for parcels of land which are flagged to be shown in search - - The event is raised when a response is received from the simulator - - A string containing a list of keywords to search for separated by a space character - A set of flags which can be ORed to modify query options - such as classified maturity rating. - The category to search - Each request is limited to 100 places - being returned. To get the first 100 result entries of a request use 0, - from 100-199 use 1, 200-299 use 2, etc. - A UUID to correlate the results when the event is raised - - Search places containing the key words "foo" and "bar" in the "Any" category that are either PG or Adult - - UUID searchID = StartDirPlacesSearch("foo bar", DirFindFlags.DwellSort | DirFindFlags.IncludePG | DirFindFlags.IncludeAdult, ParcelCategory.Any, 0); - - - - Additional information on the results can be obtained by using the ParcelManager.InfoRequest method - - - - - Starts a search for land sales using the directory - - The event is raised when a response is received from the simulator - - What type of land to search for. Auction, - estate, mainland, "first land", etc - The OnDirLandReply event handler must be registered before - calling this function. There is no way to determine how many - results will be returned, or how many times the callback will be - fired other than you won't get more than 100 total parcels from - each query. - - - - Starts a search for land sales using the directory - - The event is raised when a response is received from the simulator - - What type of land to search for. Auction, - estate, mainland, "first land", etc - Maximum price to search for - Maximum area to search for - Each request is limited to 100 parcels - being returned. To get the first 100 parcels of a request use 0, - from 100-199 use 1, 200-299 use 2, etc. - The OnDirLandReply event handler must be registered before - calling this function. There is no way to determine how many - results will be returned, or how many times the callback will be - fired other than you won't get more than 100 total parcels from - each query. - - - - Send a request to the data server for land sales listings - - - Flags sent to specify query options - - Available flags: - Specify the parcel rating with one or more of the following: - IncludePG IncludeMature IncludeAdult - - Specify the field to pre sort the results with ONLY ONE of the following: - PerMeterSort NameSort AreaSort PricesSort - - Specify the order the results are returned in, if not specified the results are pre sorted in a Descending Order - SortAsc - - Specify additional filters to limit the results with one or both of the following: - LimitByPrice LimitByArea - - Flags can be combined by separating them with the | (pipe) character - - Additional details can be found in - - What type of land to search for. Auction, - Estate or Mainland - Maximum price to search for when the - DirFindFlags.LimitByPrice flag is specified in findFlags - Maximum area to search for when the - DirFindFlags.LimitByArea flag is specified in findFlags - Each request is limited to 100 parcels - being returned. To get the first 100 parcels of a request use 0, - from 100-199 use 100, 200-299 use 200, etc. - The event will be raised with the response from the simulator - - There is no way to determine how many results will be returned, or how many times the callback will be - fired other than you won't get more than 100 total parcels from - each reply. - - Any land set for sale to either anybody or specific to the connected agent will be included in the - results if the land is included in the query - - - // request all mainland, any maturity rating that is larger than 512 sq.m - StartLandSearch(DirFindFlags.SortAsc | DirFindFlags.PerMeterSort | DirFindFlags.LimitByArea | DirFindFlags.IncludePG | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult, SearchTypeFlags.Mainland, 0, 512, 0); - - - - - Search for Groups - - The name or portion of the name of the group you wish to search for - Start from the match number - - - - - Search for Groups - - The name or portion of the name of the group you wish to search for - Start from the match number - Search flags - - - - - Search the People directory for other avatars - - The name or portion of the name of the avatar you wish to search for - - - - - - Search Places for parcels of land you personally own - - - - - Searches Places for land owned by the specified group - - ID of the group you want to recieve land list for (You must be a member of the group) - Transaction (Query) ID which can be associated with results from your request. - - - - Search the Places directory for parcels that are listed in search and contain the specified keywords - - A string containing the keywords to search for - Transaction (Query) ID which can be associated with results from your request. - - - - Search Places - All Options - - One of the Values from the DirFindFlags struct, ie: AgentOwned, GroupOwned, etc. - One of the values from the SearchCategory Struct, ie: Any, Linden, Newcomer - A string containing a list of keywords to search for separated by a space character - String Simulator Name to search in - LLUID of group you want to recieve results for - Transaction (Query) ID which can be associated with results from your request. - Transaction (Query) ID which can be associated with results from your request. - - - - Search All Events with specifid searchText in all categories, includes PG, Mature and Adult - - A string containing a list of keywords to search for separated by a space character - Each request is limited to 100 entries - being returned. To get the first group of entries of a request use 0, - from 100-199 use 100, 200-299 use 200, etc. - UUID of query to correlate results in callback. - - - - Search Events - - A string containing a list of keywords to search for separated by a space character - One or more of the following flags: DateEvents, IncludePG, IncludeMature, IncludeAdult - from the Enum - - Multiple flags can be combined by separating the flags with the | (pipe) character - "u" for in-progress and upcoming events, -or- number of days since/until event is scheduled - For example "0" = Today, "1" = tomorrow, "2" = following day, "-1" = yesterday, etc. - Each request is limited to 100 entries - being returned. To get the first group of entries of a request use 0, - from 100-199 use 100, 200-299 use 200, etc. - EventCategory event is listed under. - UUID of query to correlate results in callback. - - - Requests Event Details - ID of Event returned from the method - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming event message - The Unique Capabilities Key - The event message containing the data - The simulator the message originated from - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming event message - The Unique Capabilities Key - The event message containing the data - The simulator the message originated from - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Classified Ad categories - - - Classified is listed in the Any category - - - Classified is shopping related - - - Classified is - - - - - - - - - - - - - - - - - - - - - - - - Event Categories - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Query Flags used in many of the DirectoryManager methods to specify which query to execute and how to return the results. - - Flags can be combined using the | (pipe) character, not all flags are available in all queries - - - - Query the People database - - - - - - - - - Query the Groups database - - - Query the Events database - - - Query the land holdings database for land owned by the currently connected agent - - - - - - Query the land holdings database for land which is owned by a Group - - - Specifies the query should pre sort the results based upon traffic - when searching the Places database - - - - - - - - - - - - - - - Specifies the query should pre sort the results in an ascending order when searching the land sales database. - This flag is only used when searching the land sales database - - - Specifies the query should pre sort the results using the SalePrice field when searching the land sales database. - This flag is only used when searching the land sales database - - - Specifies the query should pre sort the results by calculating the average price/sq.m (SalePrice / Area) when searching the land sales database. - This flag is only used when searching the land sales database - - - Specifies the query should pre sort the results using the ParcelSize field when searching the land sales database. - This flag is only used when searching the land sales database - - - Specifies the query should pre sort the results using the Name field when searching the land sales database. - This flag is only used when searching the land sales database - - - When set, only parcels less than the specified Price will be included when searching the land sales database. - This flag is only used when searching the land sales database - - - When set, only parcels greater than the specified Size will be included when searching the land sales database. - This flag is only used when searching the land sales database - - - - - - - - - Include PG land in results. This flag is used when searching both the Groups, Events and Land sales databases - - - Include Mature land in results. This flag is used when searching both the Groups, Events and Land sales databases - - - Include Adult land in results. This flag is used when searching both the Groups, Events and Land sales databases - - - - - - - Land types to search dataserver for - - - - Search Auction, Mainland and Estate - - - Land which is currently up for auction - - - Parcels which are on the mainland (Linden owned) continents - - - Parcels which are on privately owned simulators - - - - The content rating of the event - - - - Event is PG - - - Event is Mature - - - Event is Adult - - - - Classified Ad Options - - There appear to be two formats the flags are packed in. - This set of flags is for the newer style - - - - - - - - - - - - - - - - - - - Classified ad query options - - - - Include all ads in results - - - Include PG ads in results - - - Include Mature ads in results - - - Include Adult ads in results - - - - The For Sale flag in PlacesReplyData - - - - Parcel is not listed for sale - - - Parcel is For Sale - - - - A classified ad on the grid - - - - UUID for this ad, useful for looking up detailed - information about it - - - The title of this classified ad - - - Flags that show certain options applied to the classified - - - Creation date of the ad - - - Expiration date of the ad - - - Price that was paid for this ad - - - Print the struct data as a string - A string containing the field name, and field value - - - - A parcel retrieved from the dataserver such as results from the - "For-Sale" listings or "Places" Search - - - - The unique dataserver parcel ID - This id is used to obtain additional information from the entry - by using the method - - - A string containing the name of the parcel - - - The size of the parcel - This field is not returned for Places searches - - - The price of the parcel - This field is not returned for Places searches - - - If True, this parcel is flagged to be auctioned - - - If true, this parcel is currently set for sale - - - Parcel traffic - - - Print the struct data as a string - A string containing the field name, and field value - - - - An Avatar returned from the dataserver - - - - Online status of agent - This field appears to be obsolete and always returns false - - - The agents first name - - - The agents last name - - - The agents - - - Print the struct data as a string - A string containing the field name, and field value - - - - Response to a "Groups" Search - - - - The Group ID - - - The name of the group - - - The current number of members - - - Print the struct data as a string - A string containing the field name, and field value - - - - Parcel information returned from a request - - Represents one of the following: - A parcel of land on the grid that has its Show In Search flag set - A parcel of land owned by the agent making the request - A parcel of land owned by a group the agent making the request is a member of - - - In a request for Group Land, the First record will contain an empty record - - Note: This is not the same as searching the land for sale data source - - - - The ID of the Agent of Group that owns the parcel - - - The name - - - The description - - - The Size of the parcel - - - The billable Size of the parcel, for mainland - parcels this will match the ActualArea field. For Group owned land this will be 10 percent smaller - than the ActualArea. For Estate land this will always be 0 - - - Indicates the ForSale status of the parcel - - - The Gridwide X position - - - The Gridwide Y position - - - The Z position of the parcel, or 0 if no landing point set - - - The name of the Region the parcel is located in - - - The Asset ID of the parcels Snapshot texture - - - The calculated visitor traffic - - - The billing product SKU - Known values are: - - 023Mainland / Full Region - 024Estate / Full Region - 027Estate / Openspace - 029Estate / Homestead - 129Mainland / Homestead (Linden Owned) - - - - - No longer used, will always be 0 - - - Get a SL URL for the parcel - A string, containing a standard SLURL - - - Print the struct data as a string - A string containing the field name, and field value - - - - An "Event" Listing summary - - - - The ID of the event creator - - - The name of the event - - - The events ID - - - A string containing the short date/time the event will begin - - - The event start time in Unixtime (seconds since epoch) - - - The events maturity rating - - - Print the struct data as a string - A string containing the field name, and field value - - - - The details of an "Event" - - - - The events ID - - - The ID of the event creator - - - The name of the event - - - The category - - - The events description - - - The short date/time the event will begin - - - The event start time in Unixtime (seconds since epoch) UTC adjusted - - - The length of the event in minutes - - - 0 if no cover charge applies - - - The cover charge amount in L$ if applicable - - - The name of the region where the event is being held - - - The gridwide location of the event - - - The maturity rating - - - Get a SL URL for the parcel where the event is hosted - A string, containing a standard SLURL - - - Print the struct data as a string - A string containing the field name, and field value - - - Contains the Event data returned from the data server from an EventInfoRequest - - - Construct a new instance of the EventInfoReplyEventArgs class - A single EventInfo object containing the details of an event - - - - A single EventInfo object containing the details of an event - - - - Contains the "Event" detail data returned from the data server - - - Construct a new instance of the DirEventsReplyEventArgs class - The ID of the query returned by the data server. - This will correlate to the ID returned by the method - A list containing the "Events" returned by the search query - - - The ID returned by - - - A list of "Events" returned by the data server - - - Contains the "Event" list data returned from the data server - - - Construct a new instance of PlacesReplyEventArgs class - The ID of the query returned by the data server. - This will correlate to the ID returned by the method - A list containing the "Places" returned by the data server query - - - The ID returned by - - - A list of "Places" returned by the data server - - - Contains the places data returned from the data server - - - Construct a new instance of the DirPlacesReplyEventArgs class - The ID of the query returned by the data server. - This will correlate to the ID returned by the method - A list containing land data returned by the data server - - - The ID returned by - - - A list containing Places data returned by the data server - - - Contains the classified data returned from the data server - - - Construct a new instance of the DirClassifiedsReplyEventArgs class - A list of classified ad data returned from the data server - - - A list containing Classified Ads returned by the data server - - - Contains the group data returned from the data server - - - Construct a new instance of the DirGroupsReplyEventArgs class - The ID of the query returned by the data server. - This will correlate to the ID returned by the method - A list of groups data returned by the data server - - - The ID returned by - - - A list containing Groups data returned by the data server - - - Contains the people data returned from the data server - - - Construct a new instance of the DirPeopleReplyEventArgs class - The ID of the query returned by the data server. - This will correlate to the ID returned by the method - A list of people data returned by the data server - - - The ID returned by - - - A list containing People data returned by the data server - - - Contains the land sales data returned from the data server - - - Construct a new instance of the DirLandReplyEventArgs class - A list of parcels for sale returned by the data server - - - A list containing land forsale data returned by the data server - - - - Represends individual HTTP Download request - - - - URI of the item to fetch - - - Timout specified in milliseconds - - - Download progress callback - - - Download completed callback - - - Accept the following content type - - - How many times will this request be retried - - - Current fetch attempt - - - Default constructor - - - Constructor - - - - Manages async HTTP downloads with a limit on maximum - concurrent downloads - - - - Default constructor - - - Cleanup method - - - Setup http download request - - - Check the queue for pending work - - - Enqueue a new HTTP download - - - Maximum number of parallel downloads from a single endpoint - - - Client certificate - - - Describes tasks returned in LandStatReply - - - - Estate level administration and utilities - - - - Textures for each of the four terrain height levels - - - Upper/lower texture boundaries for each corner of the sim - - - - Constructor for EstateTools class - - - - - The event subscribers. null if no subcribers - - - Raises the TopCollidersReply event - A TopCollidersReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the TopScriptsReply event - A TopScriptsReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the EstateUsersReply event - A EstateUsersReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the EstateGroupsReply event - A EstateGroupsReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the EstateManagersReply event - A EstateManagersReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the EstateBansReply event - A EstateBansReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the EstateCovenantReply event - A EstateCovenantReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the EstateUpdateInfoReply event - A EstateUpdateInfoReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - - Requests estate information such as top scripts and colliders - - - - - - - - Requests estate settings, including estate manager and access/ban lists - - - Requests the "Top Scripts" list for the current region - - - Requests the "Top Colliders" list for the current region - - - - Set several estate specific configuration variables - - The Height of the waterlevel over the entire estate. Defaults to 20 - The maximum height change allowed above the baked terrain. Defaults to 4 - The minimum height change allowed below the baked terrain. Defaults to -4 - true to use - if True forces the sun position to the position in SunPosition - The current position of the sun on the estate, or when FixedSun is true the static position - the sun will remain. 6.0 = Sunrise, 30.0 = Sunset - - - - Request return of objects owned by specified avatar - - The Agents owning the primitives to return - specify the coverage and type of objects to be included in the return - true to perform return on entire estate - - - - - - - - - Used for setting and retrieving various estate panel settings - - EstateOwnerMessage Method field - List of parameters to include - - - - Kick an avatar from an estate - - Key of Agent to remove - - - - Ban an avatar from an estate - Key of Agent to remove - Ban user from this estate and all others owned by the estate owner - - - Unban an avatar from an estate - Key of Agent to remove - /// Unban user from this estate and all others owned by the estate owner - - - - Send a message dialog to everyone in an entire estate - - Message to send all users in the estate - - - - Send a message dialog to everyone in a simulator - - Message to send all users in the simulator - - - - Send an avatar back to their home location - - Key of avatar to send home - - - - Begin the region restart process - - - - - Cancels a region restart - - - - Estate panel "Region" tab settings - - - Estate panel "Debug" tab settings - - - Used for setting the region's terrain textures for its four height levels - - - - - - - Used for setting sim terrain texture heights - - - Requests the estate covenant - - - - Upload a terrain RAW file - - A byte array containing the encoded terrain data - The name of the file being uploaded - The Id of the transfer request - - - - Teleports all users home in current Estate - - - - - Remove estate manager - Key of Agent to Remove - removes manager to this estate and all others owned by the estate owner - - - - Add estate manager - Key of Agent to Add - Add agent as manager to this estate and all others owned by the estate owner - - - - Add's an agent to the estate Allowed list - Key of Agent to Add - Add agent as an allowed reisdent to All estates if true - - - - Removes an agent from the estate Allowed list - Key of Agent to Remove - Removes agent as an allowed reisdent from All estates if true - - - - - Add's a group to the estate Allowed list - Key of Group to Add - Add Group as an allowed group to All estates if true - - - - - Removes a group from the estate Allowed list - Key of Group to Remove - Removes Group as an allowed Group from All estates if true - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Raised when the data server responds to a request. - - - Used in the ReportType field of a LandStatRequest - - - Used by EstateOwnerMessage packets - - - Used by EstateOwnerMessage packets - - - - - - - - No flags set - - - Only return targets scripted objects - - - Only return targets objects if on others land - - - Returns target's scripted objects and objects on other parcels - - - Ground texture settings for each corner of the region - - - Used by GroundTextureHeightSettings - - - The high and low texture thresholds for each corner of the sim - - - Raised on LandStatReply when the report type is for "top colliders" - - - Construct a new instance of the TopCollidersReplyEventArgs class - The number of returned items in LandStatReply - Dictionary of Object UUIDs to tasks returned in LandStatReply - - - - The number of returned items in LandStatReply - - - - - A Dictionary of Object UUIDs to tasks returned in LandStatReply - - - - Raised on LandStatReply when the report type is for "top Scripts" - - - Construct a new instance of the TopScriptsReplyEventArgs class - The number of returned items in LandStatReply - Dictionary of Object UUIDs to tasks returned in LandStatReply - - - - The number of scripts returned in LandStatReply - - - - - A Dictionary of Object UUIDs to tasks returned in LandStatReply - - - - Returned, along with other info, upon a successful .RequestInfo() - - - Construct a new instance of the EstateBansReplyEventArgs class - The estate's identifier on the grid - The number of returned items in LandStatReply - User UUIDs banned - - - - The identifier of the estate - - - - - The number of returned itmes - - - - - List of UUIDs of Banned Users - - - - Returned, along with other info, upon a successful .RequestInfo() - - - Construct a new instance of the EstateUsersReplyEventArgs class - The estate's identifier on the grid - The number of users - Allowed users UUIDs - - - - The identifier of the estate - - - - - The number of returned items - - - - - List of UUIDs of Allowed Users - - - - Returned, along with other info, upon a successful .RequestInfo() - - - Construct a new instance of the EstateGroupsReplyEventArgs class - The estate's identifier on the grid - The number of Groups - Allowed Groups UUIDs - - - - The identifier of the estate - - - - - The number of returned items - - - - - List of UUIDs of Allowed Groups - - - - Returned, along with other info, upon a successful .RequestInfo() - - - Construct a new instance of the EstateManagersReplyEventArgs class - The estate's identifier on the grid - The number of Managers - Managers UUIDs - - - - The identifier of the estate - - - - - The number of returned items - - - - - List of UUIDs of the Estate's Managers - - - - Returned, along with other info, upon a successful .RequestInfo() - - - Construct a new instance of the EstateCovenantReplyEventArgs class - The Covenant ID - The timestamp - The estate's name - The Estate Owner's ID (can be a GroupID) - - - - The Covenant - - - - - The timestamp - - - - - The Estate name - - - - - The Estate Owner's ID (can be a GroupID) - - - - Returned, along with other info, upon a successful .RequestInfo() - - - Construct a new instance of the EstateUpdateInfoReplyEventArgs class - The estate's name - The Estate Owners ID (can be a GroupID) - The estate's identifier on the grid - - - - - The estate's name - - - - - The Estate Owner's ID (can be a GroupID) - - - - - The identifier of the estate on the grid - - - - - - - - Registers, unregisters, and fires events generated by incoming packets - - - - Reference to the GridClient object - - - - Default constructor - - - - - - Register an event handler - - Use PacketType.Default to fire this event on every - incoming packet - Packet type to register the handler for - Callback to be fired - True if this callback should be ran - asynchronously, false to run it synchronous - - - - Unregister an event handler - - Packet type to unregister the handler for - Callback to be unregistered - - - - Fire the events registered for this packet type - - Incoming packet type - Incoming packet - Simulator this packet was received from - - - - Object that is passed to worker threads in the ThreadPool for - firing packet callbacks - - - - Callback to fire for this packet - - - Reference to the simulator that this packet came from - - - The packet that needs to be processed - - - - Registers, unregisters, and fires events generated by the Capabilities - event queue - - - - Reference to the GridClient object - - - - Default constructor - - Reference to the GridClient object - - - - Register an new event handler for a capabilities event sent via the EventQueue - - Use String.Empty to fire this event on every CAPS event - Capability event name to register the - handler for - Callback to fire - - - - Unregister a previously registered capabilities handler - - Capability event name unregister the - handler for - Callback to unregister - - - - Fire the events registered for this event type synchronously - - Capability name - Decoded event body - Reference to the simulator that - generated this event - - - - Fire the events registered for this event type asynchronously - - Capability name - Decoded event body - Reference to the simulator that - generated this event - - - - Object that is passed to worker threads in the ThreadPool for - firing CAPS callbacks - - - - Callback to fire for this packet - - - Name of the CAPS event - - - Strongly typed decoded data - - - Reference to the simulator that generated this event - - - - - - - - The avatar has no rights - - - The avatar can see the online status of the target avatar - - - The avatar can see the location of the target avatar on the map - - - The avatar can modify the ojects of the target avatar - - - - This class holds information about an avatar in the friends list. There are two ways - to interface to this class. The first is through the set of boolean properties. This is the typical - way clients of this class will use it. The second interface is through two bitflag properties, - TheirFriendsRights and MyFriendsRights - - - - - Used internally when building the initial list of friends at login time - - System ID of the avatar being prepesented - Rights the friend has to see you online and to modify your objects - Rights you have to see your friend online and to modify their objects - - - - FriendInfo represented as a string - - A string reprentation of both my rights and my friends rights - - - - System ID of the avatar - - - - - full name of the avatar - - - - - True if the avatar is online - - - - - True if the friend can see if I am online - - - - - True if the friend can see me on the map - - - - - True if the freind can modify my objects - - - - - True if I can see if my friend is online - - - - - True if I can see if my friend is on the map - - - - - True if I can modify my friend's objects - - - - - My friend's rights represented as bitmapped flags - - - - - My rights represented as bitmapped flags - - - - - This class is used to add and remove avatars from your friends list and to manage their permission. - - - - The event subscribers. null if no subcribers - - - Raises the FriendOnline event - A FriendInfoEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the FriendOffline event - A FriendInfoEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the FriendRightsUpdate event - A FriendInfoEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the FriendNames event - A FriendNamesEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the FriendshipOffered event - A FriendshipOfferedEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the FriendshipResponse event - A FriendshipResponseEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the FriendshipTerminated event - A FriendshipTerminatedEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the FriendFoundReply event - A FriendFoundReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - - A dictionary of key/value pairs containing known friends of this avatar. - - The Key is the of the friend, the value is a - object that contains detailed information including permissions you have and have given to the friend - - - - - A Dictionary of key/value pairs containing current pending frienship offers. - - The key is the of the avatar making the request, - the value is the of the request which is used to accept - or decline the friendship offer - - - - - Internal constructor - - A reference to the GridClient Object - - - - Accept a friendship request - - agentID of avatatar to form friendship with - imSessionID of the friendship request message - - - - Decline a friendship request - - of friend - imSessionID of the friendship request message - - - - Overload: Offer friendship to an avatar. - - System ID of the avatar you are offering friendship to - - - - Offer friendship to an avatar. - - System ID of the avatar you are offering friendship to - A message to send with the request - - - - Terminate a friendship with an avatar - - System ID of the avatar you are terminating the friendship with - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - - Change the rights of a friend avatar. - - the of the friend - the new rights to give the friend - This method will implicitly set the rights to those passed in the rights parameter. - - - - Use to map a friends location on the grid. - - Friends UUID to find - - - - - Use to track a friends movement on the grid - - Friends Key - - - - Ask for a notification of friend's online status - - Friend's UUID - - - - This handles the asynchronous response of a RequestAvatarNames call. - - - names cooresponding to the the list of IDs sent the the RequestAvatarNames call. - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - - Populate FriendList with data from the login reply - - true if login was successful - true if login request is requiring a redirect - A string containing the response to the login request - A string containing the reason for the request - A object containing the decoded - reply from the login server - - - Raised when the simulator sends notification one of the members in our friends list comes online - - - Raised when the simulator sends notification one of the members in our friends list goes offline - - - Raised when the simulator sends notification one of the members in our friends list grants or revokes permissions - - - Raised when the simulator sends us the names on our friends list - - - Raised when the simulator sends notification another agent is offering us friendship - - - Raised when a request we sent to friend another agent is accepted or declined - - - Raised when the simulator sends notification one of the members in our friends list has terminated - our friendship - - - Raised when the simulator sends the location of a friend we have - requested map location info for - - - Contains information on a member of our friends list - - - - Construct a new instance of the FriendInfoEventArgs class - - The FriendInfo - - - Get the FriendInfo - - - Contains Friend Names - - - - Construct a new instance of the FriendNamesEventArgs class - - A dictionary where the Key is the ID of the Agent, - and the Value is a string containing their name - - - A dictionary where the Key is the ID of the Agent, - and the Value is a string containing their name - - - Sent when another agent requests a friendship with our agent - - - - Construct a new instance of the FriendshipOfferedEventArgs class - - The ID of the agent requesting friendship - The name of the agent requesting friendship - The ID of the session, used in accepting or declining the - friendship offer - - - Get the ID of the agent requesting friendship - - - Get the name of the agent requesting friendship - - - Get the ID of the session, used in accepting or declining the - friendship offer - - - A response containing the results of our request to form a friendship with another agent - - - - Construct a new instance of the FriendShipResponseEventArgs class - - The ID of the agent we requested a friendship with - The name of the agent we requested a friendship with - true if the agent accepted our friendship offer - - - Get the ID of the agent we requested a friendship with - - - Get the name of the agent we requested a friendship with - - - true if the agent accepted our friendship offer - - - Contains data sent when a friend terminates a friendship with us - - - - Construct a new instance of the FrindshipTerminatedEventArgs class - - The ID of the friend who terminated the friendship with us - The name of the friend who terminated the friendship with us - - - Get the ID of the agent that terminated the friendship with us - - - Get the name of the agent that terminated the friendship with us - - - - Data sent in response to a request which contains the information to allow us to map the friends location - - - - - Construct a new instance of the FriendFoundReplyEventArgs class - - The ID of the agent we have requested location information for - The region handle where our friend is located - The simulator local position our friend is located - - - Get the ID of the agent we have received location information for - - - Get the region handle where our mapped friend is located - - - Get the simulator local position where our friend is located - - - - Main class to expose grid functionality to clients. All of the - classes needed for sending and receiving data are accessible through - this class. - - - - // Example minimum code required to instantiate class and - // connect to a simulator. - using System; - using System.Collections.Generic; - using System.Text; - using OpenMetaverse; - - namespace FirstBot - { - class Bot - { - public static GridClient Client; - static void Main(string[] args) - { - Client = new GridClient(); // instantiates the GridClient class - // to the global Client object - // Login to Simulator - Client.Network.Login("FirstName", "LastName", "Password", "FirstBot", "1.0"); - // Wait for a Keypress - Console.ReadLine(); - // Logout of simulator - Client.Network.Logout(); - } - } - } - - - - - Networking subsystem - - - Settings class including constant values and changeable - parameters for everything - - - Parcel (subdivided simulator lots) subsystem - - - Our own avatars subsystem - - - Other avatars subsystem - - - Estate subsystem - - - Friends list subsystem - - - Grid (aka simulator group) subsystem - - - Object subsystem - - - Group subsystem - - - Asset subsystem - - - Appearance subsystem - - - Inventory subsystem - - - Directory searches including classifieds, people, land - sales, etc - - - Handles land, wind, and cloud heightmaps - - - Handles sound-related networking - - - Throttling total bandwidth usage, or allocating bandwidth - for specific data stream types - - - - Default constructor - - - - - Return the full name of this instance - - Client avatars full name - - - - Map layer request type - - - - Objects and terrain are shown - - - Only the terrain is shown, no objects - - - Overlay showing land for sale and for auction - - - - Type of grid item, such as telehub, event, populator location, etc. - - - - Telehub - - - PG rated event - - - Mature rated event - - - Popular location - - - Locations of avatar groups in a region - - - Land for sale - - - Classified ad - - - Adult rated event - - - Adult land for sale - - - - Information about a region on the grid map - - - - Sim X position on World Map - - - Sim Y position on World Map - - - Sim Name (NOTE: In lowercase!) - - - - - - Appears to always be zero (None) - - - Sim's defined Water Height - - - - - - UUID of the World Map image - - - Unique identifier for this region, a combination of the X - and Y position - - - - - - - - - - - - - - - - - - - - - - - Visual chunk of the grid map - - - - - Base class for Map Items - - - - The Global X position of the item - - - The Global Y position of the item - - - Get the Local X position of the item - - - Get the Local Y position of the item - - - Get the Handle of the region - - - - Represents an agent or group of agents location - - - - - Represents a Telehub location - - - - - Represents a non-adult parcel of land for sale - - - - - Represents an Adult parcel of land for sale - - - - - Represents a PG Event - - - - - Represents a Mature event - - - - - Represents an Adult event - - - - - Manages grid-wide tasks such as the world map - - - - The event subscribers. null if no subcribers - - - Raises the CoarseLocationUpdate event - A CoarseLocationUpdateEventArgs object containing the - data sent by simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GridRegion event - A GridRegionEventArgs object containing the - data sent by simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GridLayer event - A GridLayerEventArgs object containing the - data sent by simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GridItems event - A GridItemEventArgs object containing the - data sent by simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the RegionHandleReply event - A RegionHandleReplyEventArgs object containing the - data sent by simulator - - - Thread sync lock object - - - A dictionary of all the regions, indexed by region name - - - A dictionary of all the regions, indexed by region handle - - - - Constructor - - Instance of GridClient object to associate with this GridManager instance - - - - - - - - - - Request a map layer - - The name of the region - The type of layer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Request data for all mainland (Linden managed) simulators - - - - - Request the region handle for the specified region UUID - - UUID of the region to look up - - - - Get grid region information using the region name, this function - will block until it can find the region or gives up - - Name of sim you're looking for - Layer that you are requesting - Will contain a GridRegion for the sim you're - looking for if successful, otherwise an empty structure - True if the GridRegion was successfully fetched, otherwise - false - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Raised when the simulator sends a - containing the location of agents in the simulator - - - Raised when the simulator sends a Region Data in response to - a Map request - - - Raised when the simulator sends GridLayer object containing - a map tile coordinates and texture information - - - Raised when the simulator sends GridItems object containing - details on events, land sales at a specific location - - - Raised in response to a Region lookup - - - Unknown - - - Current direction of the sun - - - Current angular velocity of the sun - - - Microseconds since the start of SL 4-hour day - - - - Avatar group management - - - - Key of Group Member - - - Total land contribution - - - Online status information - - - Abilities that the Group Member has - - - Current group title - - - Is a group owner - - - - Role manager for a group - - - - Key of the group - - - Key of Role - - - Name of Role - - - Group Title associated with Role - - - Description of Role - - - Abilities Associated with Role - - - Returns the role's title - The role's title - - - - Class to represent Group Title - - - - Key of the group - - - ID of the role title belongs to - - - Group Title - - - Whether title is Active - - - Returns group title - - - - Represents a group on the grid - - - - Key of Group - - - Key of Group Insignia - - - Key of Group Founder - - - Key of Group Role for Owners - - - Name of Group - - - Text of Group Charter - - - Title of "everyone" role - - - Is the group open for enrolement to everyone - - - Will group show up in search - - - - - - - - - - - - Is the group Mature - - - Cost of group membership - - - - - - - - - The total number of current members this group has - - - The number of roles this group has configured - - - Show this group in agent's profile - - - Returns the name of the group - A string containing the name of the group - - - - A group Vote - - - - Key of Avatar who created Vote - - - Text of the Vote proposal - - - Total number of votes - - - - A group proposal - - - - The Text of the proposal - - - The minimum number of members that must vote before proposal passes or failes - - - The required ration of yes/no votes required for vote to pass - The three options are Simple Majority, 2/3 Majority, and Unanimous - TODO: this should be an enum - - - The duration in days votes are accepted - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Struct representing a group notice - - - - - - - - - - - - - - - - - - - - - - - Struct representing a group notice list entry - - - - Notice ID - - - Creation timestamp of notice - - - Agent name who created notice - - - Notice subject - - - Is there an attachment? - - - Attachment Type - - - - Struct representing a member of a group chat session and their settings - - - - The of the Avatar - - - True if user has voice chat enabled - - - True of Avatar has moderator abilities - - - True if a moderator has muted this avatars chat - - - True if a moderator has muted this avatars voice - - - - Role update flags - - - - - - - - - - - - - - - - - - - - - - - - - Can send invitations to groups default role - - - Can eject members from group - - - Can toggle 'Open Enrollment' and change 'Signup fee' - - - Member is visible in the public member list - - - Can create new roles - - - Can delete existing roles - - - Can change Role names, titles and descriptions - - - Can assign other members to assigners role - - - Can assign other members to any role - - - Can remove members from roles - - - Can assign and remove abilities in roles - - - Can change group Charter, Insignia, 'Publish on the web' and which - members are publicly visible in group member listings - - - Can buy land or deed land to group - - - Can abandon group owned land to Governor Linden on mainland, or Estate owner for - private estates - - - Can set land for-sale information on group owned parcels - - - Can subdivide and join parcels - - - Can join group chat sessions - - - Can use voice chat in Group Chat sessions - - - Can moderate group chat sessions - - - Can toggle "Show in Find Places" and set search category - - - Can change parcel name, description, and 'Publish on web' settings - - - Can set the landing point and teleport routing on group land - - - Can change music and media settings - - - Can toggle 'Edit Terrain' option in Land settings - - - Can toggle various About Land > Options settings - - - Can always terraform land, even if parcel settings have it turned off - - - Can always fly while over group owned land - - - Can always rez objects on group owned land - - - Can always create landmarks for group owned parcels - - - Can set home location on any group owned parcel - - - Can modify public access settings for group owned parcels - - - Can manager parcel ban lists on group owned land - - - Can manage pass list sales information - - - Can eject and freeze other avatars on group owned land - - - Can return objects set to group - - - Can return non-group owned/set objects - - - Can return group owned objects - - - Can landscape using Linden plants - - - Can deed objects to group - - - Can move group owned objects - - - Can set group owned objects for-sale - - - Pay group liabilities and receive group dividends - - - List and Host group events - - - Can send group notices - - - Can receive group notices - - - Can create group proposals - - - Can vote on group proposals - - - - Ban actions available for group members - - - - Ban agent from joining a group - - - Remove restriction on agent jointing a group - - - - Handles all network traffic related to reading and writing group - information - - - - The event subscribers. null if no subcribers - - - Raises the CurrentGroups event - A CurrentGroupsEventArgs object containing the - data sent from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupNamesReply event - A GroupNamesEventArgs object containing the - data response from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupProfile event - An GroupProfileEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupMembers event - A GroupMembersEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupRolesDataReply event - A GroupRolesDataReplyEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupRoleMembersReply event - A GroupRolesRoleMembersReplyEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupTitlesReply event - A GroupTitlesReplyEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupAccountSummary event - A GroupAccountSummaryReplyEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupCreated event - An GroupCreatedEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupJoined event - A GroupOperationEventArgs object containing the - result of the operation returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupLeft event - A GroupOperationEventArgs object containing the - result of the operation returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupDropped event - An GroupDroppedEventArgs object containing the - the group your agent left - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupMemberEjected event - An GroupMemberEjectedEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupNoticesListReply event - An GroupNoticesListReplyEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the GroupInvitation event - An GroupInvitationEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the BannedAgents event - An BannedAgentsEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - A reference to the current instance - - - Currently-active group members requests - - - Currently-active group roles requests - - - Currently-active group role-member requests - - - Dictionary keeping group members while request is in progress - - - Dictionary keeping mebmer/role mapping while request is in progress - - - Dictionary keeping GroupRole information while request is in progress - - - Caches group name lookups - - - - Construct a new instance of the GroupManager class - - A reference to the current instance - - - - Request a current list of groups the avatar is a member of. - - CAPS Event Queue must be running for this to work since the results - come across CAPS. - - - - Lookup name of group based on groupID - - groupID of group to lookup name for. - - - - Request lookup of multiple group names - - List of group IDs to request. - - - Lookup group profile data such as name, enrollment, founder, logo, etc - Subscribe to OnGroupProfile event to receive the results. - group ID (UUID) - - - Request a list of group members. - Subscribe to OnGroupMembers event to receive the results. - group ID (UUID) - UUID of the request, use to index into cache - - - Request group roles - Subscribe to OnGroupRoles event to receive the results. - group ID (UUID) - UUID of the request, use to index into cache - - - Request members (members,role) role mapping for a group. - Subscribe to OnGroupRolesMembers event to receive the results. - group ID (UUID) - UUID of the request, use to index into cache - - - Request a groups Titles - Subscribe to OnGroupTitles event to receive the results. - group ID (UUID) - UUID of the request, use to index into cache - - - Begin to get the group account summary - Subscribe to the OnGroupAccountSummary event to receive the results. - group ID (UUID) - How long of an interval - Which interval (0 for current, 1 for last) - - - Invites a user to a group - The group to invite to - A list of roles to invite a person to - Key of person to invite - - - Set a group as the current active group - group ID (UUID) - - - Change the role that determines your active title - Group ID to use - Role ID to change to - - - Set this avatar's tier contribution - Group ID to change tier in - amount of tier to donate - - - - Save wheather agent wants to accept group notices and list this group in their profile - - Group - Accept notices from this group - List this group in the profile - - - Request to join a group - Subscribe to OnGroupJoined event for confirmation. - group ID (UUID) to join. - - - - Request to create a new group. If the group is successfully - created, L$100 will automatically be deducted - - Subscribe to OnGroupCreated event to receive confirmation. - Group struct containing the new group info - - - Update a group's profile and other information - Groups ID (UUID) to update. - Group struct to update. - - - Eject a user from a group - Group ID to eject the user from - Avatar's key to eject - - - Update role information - Modified role to be updated - - - Create a new group role - Group ID to update - Role to create - - - Delete a group role - Group ID to update - Role to delete - - - Remove an avatar from a role - Group ID to update - Role ID to be removed from - Avatar's Key to remove - - - Assign an avatar to a role - Group ID to update - Role ID to assign to - Avatar's ID to assign to role - - - Request the group notices list - Group ID to fetch notices for - - - Request a group notice by key - ID of group notice - - - Send out a group notice - Group ID to update - GroupNotice structure containing notice data - - - Start a group proposal (vote) - The Group ID to send proposal to - GroupProposal structure containing the proposal - - - Request to leave a group - Subscribe to OnGroupLeft event to receive confirmation - The group to leave - - - - Gets the URI of the cpability for handling group bans - - Group ID - null, if the feature is not supported, or URI of the capability - - - - Request a list of residents banned from joining a group - - UUID of the group - - - - Request a list of residents banned from joining a group - - UUID of the group - Callback on request completition - - - - Request that group of agents be banned or unbanned from the group - - Group ID - Ban/Unban action - Array of agents UUIDs to ban - - - - Request that group of agents be banned or unbanned from the group - - Group ID - Ban/Unban action - Array of agents UUIDs to ban - Callback - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Raised when the simulator sends us data containing - our current group membership - - - Raised when the simulator responds to a RequestGroupName - or RequestGroupNames request - - - Raised when the simulator responds to a request - - - Raised when the simulator responds to a request - - - Raised when the simulator responds to a request - - - Raised when the simulator responds to a request - - - Raised when the simulator responds to a request - - - Raised when a response to a RequestGroupAccountSummary is returned - by the simulator - - - Raised when a request to create a group is successful - - - Raised when a request to join a group either - fails or succeeds - - - Raised when a request to leave a group either - fails or succeeds - - - Raised when A group is removed from the group server - - - Raised when a request to eject a member from a group either - fails or succeeds - - - Raised when the simulator sends us group notices - - - - Raised when another agent invites our avatar to join a group - - - Raised when another agent invites our avatar to join a group - - - Contains the current groups your agent is a member of - - - Construct a new instance of the CurrentGroupsEventArgs class - The current groups your agent is a member of - - - Get the current groups your agent is a member of - - - A Dictionary of group names, where the Key is the groups ID and the value is the groups name - - - Construct a new instance of the GroupNamesEventArgs class - The Group names dictionary - - - Get the Group Names dictionary - - - Represents the members of a group - - - - Construct a new instance of the GroupMembersReplyEventArgs class - - The ID of the request - The ID of the group - The membership list of the group - - - Get the ID as returned by the request to correlate - this result set and the request - - - Get the ID of the group - - - Get the dictionary of members - - - Represents the roles associated with a group - - - Construct a new instance of the GroupRolesDataReplyEventArgs class - The ID as returned by the request to correlate - this result set and the request - The ID of the group - The dictionary containing the roles - - - Get the ID as returned by the request to correlate - this result set and the request - - - Get the ID of the group - - - Get the dictionary containing the roles - - - Represents the Role to Member mappings for a group - - - Construct a new instance of the GroupRolesMembersReplyEventArgs class - The ID as returned by the request to correlate - this result set and the request - The ID of the group - The member to roles map - - - Get the ID as returned by the request to correlate - this result set and the request - - - Get the ID of the group - - - Get the member to roles map - - - Represents the titles for a group - - - Construct a new instance of the GroupTitlesReplyEventArgs class - The ID as returned by the request to correlate - this result set and the request - The ID of the group - The titles - - - Get the ID as returned by the request to correlate - this result set and the request - - - Get the ID of the group - - - Get the titles - - - Represents the summary data for a group - - - Construct a new instance of the GroupAccountSummaryReplyEventArgs class - The ID of the group - The summary data - - - Get the ID of the group - - - Get the summary data - - - A response to a group create request - - - Construct a new instance of the GroupCreatedReplyEventArgs class - The ID of the group - the success or faulure of the request - A string containing additional information - - - Get the ID of the group - - - true of the group was created successfully - - - A string containing the message - - - Represents a response to a request - - - Construct a new instance of the GroupOperationEventArgs class - The ID of the group - true of the request was successful - - - Get the ID of the group - - - true of the request was successful - - - Represents your agent leaving a group - - - Construct a new instance of the GroupDroppedEventArgs class - The ID of the group - - - Get the ID of the group - - - Represents a list of active group notices - - - Construct a new instance of the GroupNoticesListReplyEventArgs class - The ID of the group - The list containing active notices - - - Get the ID of the group - - - Get the notices list - - - Represents the profile of a group - - - Construct a new instance of the GroupProfileEventArgs class - The group profile - - - Get the group profile - - - - Provides notification of a group invitation request sent by another Avatar - - The invitation is raised when another avatar makes an offer for our avatar - to join a group. - - - The ID of the Avatar sending the group invitation - - - The name of the Avatar sending the group invitation - - - A message containing the request information which includes - the name of the group, the groups charter and the fee to join details - - - The Simulator - - - Set to true to accept invitation, false to decline - - - - Result of the request for list of agents banned from a group - - - - Indicates if list of banned agents for a group was successfully retrieved - - - Indicates if list of banned agents for a group was successfully retrieved - - - Array containing a list of UUIDs of the agents banned from a group - - - - Static helper functions and global variables - - - - This header flag signals that ACKs are appended to the packet - - - This header flag signals that this packet has been sent before - - - This header flags signals that an ACK is expected for this packet - - - This header flag signals that the message is compressed using zerocoding - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Given an X/Y location in absolute (grid-relative) terms, a region - handle is returned along with the local X/Y location in that region - - The absolute X location, a number such as - 255360.35 - The absolute Y location, a number such as - 255360.35 - The sim-local X position of the global X - position, a value from 0.0 to 256.0 - The sim-local Y position of the global Y - position, a value from 0.0 to 256.0 - A 64-bit region handle that can be used to teleport to - - - - Converts a floating point number to a terse string format used for - transmitting numbers in wearable asset files - - Floating point number to convert to a string - A terse string representation of the input number - - - - Convert a variable length field (byte array) to a string, with a - field name prepended to each line of the output - - If the byte array has unprintable characters in it, a - hex dump will be written instead - The StringBuilder object to write to - The byte array to convert to a string - A field name to prepend to each line of output - - - - Decode a zerocoded byte array, used to decompress packets marked - with the zerocoded flag - - Any time a zero is encountered, the next byte is a count - of how many zeroes to expand. One zero is encoded with 0x00 0x01, - two zeroes is 0x00 0x02, three zeroes is 0x00 0x03, etc. The - first four bytes are copied directly to the output buffer. - - The byte array to decode - The length of the byte array to decode. This - would be the length of the packet up to (but not including) any - appended ACKs - The output byte array to decode to - The length of the output buffer - - - - Encode a byte array with zerocoding. Used to compress packets marked - with the zerocoded flag. Any zeroes in the array are compressed down - to a single zero byte followed by a count of how many zeroes to expand - out. A single zero becomes 0x00 0x01, two zeroes becomes 0x00 0x02, - three zeroes becomes 0x00 0x03, etc. The first four bytes are copied - directly to the output buffer. - - The byte array to encode - The length of the byte array to encode - The output byte array to encode to - The length of the output buffer - - - - Calculates the CRC (cyclic redundancy check) needed to upload inventory. - - Creation date - Sale type - Inventory type - Type - Asset ID - Group ID - Sale price - Owner ID - Creator ID - Item ID - Folder ID - Everyone mask (permissions) - Flags - Next owner mask (permissions) - Group mask (permissions) - Owner mask (permissions) - The calculated CRC - - - - Attempts to load a file embedded in the assembly - - The filename of the resource to load - A Stream for the requested file, or null if the resource - was not successfully loaded - - - - Attempts to load a file either embedded in the assembly or found in - a given search path - - The filename of the resource to load - An optional path that will be searched if - the asset is not found embedded in the assembly - A Stream for the requested file, or null if the resource - was not successfully loaded - - - - Converts a list of primitives to an object that can be serialized - with the LLSD system - - Primitives to convert to a serializable object - An object that can be serialized with LLSD - - - - Deserializes OSD in to a list of primitives - - Structure holding the serialized primitive list, - must be of the SDMap type - A list of deserialized primitives - - - - Converts a struct or class object containing fields only into a key value separated string - - The struct object - A string containing the struct fields as the keys, and the field value as the value separated - - - // Add the following code to any struct or class containing only fields to override the ToString() - // method to display the values of the passed object - - /// Print the struct data as a string - ///A string containing the field name, and field value - public override string ToString() - { - return Helpers.StructToString(this); - } - - - - - - Passed to Logger.Log() to identify the severity of a log entry - - - - No logging information will be output - - - Non-noisy useful information, may be helpful in - debugging a problem - - - A non-critical error occurred. A warning will not - prevent the rest of the library from operating as usual, - although it may be indicative of an underlying issue - - - A critical error has occurred. Generally this will - be followed by the network layer shutting down, although the - stability of the library after an error is uncertain - - - Used for internal testing, this logging level can - generate very noisy (long and/or repetitive) messages. Don't - pass this to the Log() function, use DebugLog() instead. - - - - - The InternalDictionary class is used through the library for storing key/value pairs. - It is intended to be a replacement for the generic Dictionary class and should - be used in its place. It contains several methods for allowing access to the data from - outside the library that are read only and thread safe. - - - Key - Value - - - Internal dictionary that this class wraps around. Do not - modify or enumerate the contents of this dictionary without locking - on this member - - - - Initializes a new instance of the Class - with the specified key/value, has the default initial capacity. - - - - // initialize a new InternalDictionary named testDict with a string as the key and an int as the value. - public InternalDictionary<string, int> testDict = new InternalDictionary<string, int>(); - - - - - - Initializes a new instance of the Class - with the specified key/value, has its initial valies copied from the specified - - - - to copy initial values from - - - // initialize a new InternalDictionary named testAvName with a UUID as the key and an string as the value. - // populates with copied values from example KeyNameCache Dictionary. - - // create source dictionary - Dictionary<UUID, string> KeyNameCache = new Dictionary<UUID, string>(); - KeyNameCache.Add("8300f94a-7970-7810-cf2c-fc9aa6cdda24", "Jack Avatar"); - KeyNameCache.Add("27ba1e40-13f7-0708-3e98-5819d780bd62", "Jill Avatar"); - - // Initialize new dictionary. - public InternalDictionary<UUID, string> testAvName = new InternalDictionary<UUID, string>(KeyNameCache); - - - - - - Initializes a new instance of the Class - with the specified key/value, With its initial capacity specified. - - Initial size of dictionary - - - // initialize a new InternalDictionary named testDict with a string as the key and an int as the value, - // initially allocated room for 10 entries. - public InternalDictionary<string, int> testDict = new InternalDictionary<string, int>(10); - - - - - - Try to get entry from with specified key - - Key to use for lookup - Value returned - if specified key exists, if not found - - - // find your avatar using the Simulator.ObjectsAvatars InternalDictionary: - Avatar av; - if (Client.Network.CurrentSim.ObjectsAvatars.TryGetValue(Client.Self.AgentID, out av)) - Console.WriteLine("Found Avatar {0}", av.Name); - - - - - - - Finds the specified match. - - The match. - Matched value - - - // use a delegate to find a prim in the ObjectsPrimitives InternalDictionary - // with the ID 95683496 - uint findID = 95683496; - Primitive findPrim = sim.ObjectsPrimitives.Find( - delegate(Primitive prim) { return prim.ID == findID; }); - - - - - Find All items in an - return matching items. - a containing found items. - - Find All prims within 20 meters and store them in a List - - int radius = 20; - List<Primitive> prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll( - delegate(Primitive prim) { - Vector3 pos = prim.Position; - return ((prim.ParentID == 0) && (pos != Vector3.Zero) && (Vector3.Distance(pos, location) < radius)); - } - ); - - - - - Find All items in an - return matching keys. - a containing found keys. - - Find All keys which also exist in another dictionary - - List<UUID> matches = myDict.FindAll( - delegate(UUID id) { - return myOtherDict.ContainsKey(id); - } - ); - - - - - Perform an on each entry in an - to perform - - - // Iterates over the ObjectsPrimitives InternalDictionary and prints out some information. - Client.Network.CurrentSim.ObjectsPrimitives.ForEach( - delegate(Primitive prim) - { - if (prim.Text != null) - { - Console.WriteLine("NAME={0} ID = {1} TEXT = '{2}'", - prim.PropertiesFamily.Name, prim.ID, prim.Text); - } - }); - - - - - Perform an on each key of an - to perform - - - - Perform an on each KeyValuePair of an - - to perform - - - Check if Key exists in Dictionary - Key to check for - if found, otherwise - - - Check if Value exists in Dictionary - Value to check for - if found, otherwise - - - - Adds the specified key to the dictionary, dictionary locking is not performed, - - - The key - The value - - - - Removes the specified key, dictionary locking is not performed - - The key. - if successful, otherwise - - - - Gets the number of Key/Value pairs contained in the - - - - - Indexer for the dictionary - - The key - The value - - - - Exception class to identify inventory exceptions - - - - - Responsible for maintaining inventory structure. Inventory constructs nodes - and manages node children as is necessary to maintain a coherant hirarchy. - Other classes should not manipulate or create InventoryNodes explicitly. When - A node's parent changes (when a folder is moved, for example) simply pass - Inventory the updated InventoryFolder and it will make the appropriate changes - to its internal representation. - - - - The event subscribers, null of no subscribers - - - Raises the InventoryObjectUpdated Event - A InventoryObjectUpdatedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the InventoryObjectRemoved Event - A InventoryObjectRemovedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the InventoryObjectAdded Event - A InventoryObjectAddedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - - Returns the contents of the specified folder - - A folder's UUID - The contents of the folder corresponding to folder - When folder does not exist in the inventory - - - - Updates the state of the InventoryNode and inventory data structure that - is responsible for the InventoryObject. If the item was previously not added to inventory, - it adds the item, and updates structure accordingly. If it was, it updates the - InventoryNode, changing the parent node if item.parentUUID does - not match node.Parent.Data.UUID. - - You can not set the inventory root folder using this method - - The InventoryObject to store - - - - Removes the InventoryObject and all related node data from Inventory. - - The InventoryObject to remove. - - - - Used to find out if Inventory contains the InventoryObject - specified by uuid. - - The UUID to check. - true if inventory contains uuid, false otherwise - - - - Saves the current inventory structure to a cache file - - Name of the cache file to save to - - - - Loads in inventory cache file into the inventory structure. Note only valid to call after login has been successful. - - Name of the cache file to load - The number of inventory items sucessfully reconstructed into the inventory node tree - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - - The root folder of this avatars inventory - - - - - The default shared library folder - - - - - The root node of the avatars inventory - - - - - The root node of the default shared library - - - - - By using the bracket operator on this class, the program can get the - InventoryObject designated by the specified uuid. If the value for the corresponding - UUID is null, the call is equivelant to a call to RemoveNodeFor(this[uuid]). - If the value is non-null, it is equivelant to a call to UpdateNodeFor(value), - the uuid parameter is ignored. - - The UUID of the InventoryObject to get or set, ignored if set to non-null value. - The InventoryObject corresponding to uuid. - - - Sort by name - - - Sort by date - - - Sort folders by name, regardless of whether items are - sorted by name or date - - - Place system folders at the top - - - - Possible destinations for DeRezObject request - - - - - - - Copy from in-world to agent inventory - - - Derez to TaskInventory - - - - - - Take Object - - - - - - Delete Object - - - Put an avatar attachment into agent inventory - - - - - - Return an object back to the owner's inventory - - - Return a deeded object back to the last owner's inventory - - - - Upper half of the Flags field for inventory items - - - - Indicates that the NextOwner permission will be set to the - most restrictive set of permissions found in the object set - (including linkset items and object inventory items) on next rez - - - Indicates that the object sale information has been - changed - - - If set, and a slam bit is set, indicates BaseMask will be overwritten on Rez - - - If set, and a slam bit is set, indicates OwnerMask will be overwritten on Rez - - - If set, and a slam bit is set, indicates GroupMask will be overwritten on Rez - - - If set, and a slam bit is set, indicates EveryoneMask will be overwritten on Rez - - - If set, and a slam bit is set, indicates NextOwnerMask will be overwritten on Rez - - - Indicates whether this object is composed of multiple - items or not - - - Indicates that the asset is only referenced by this - inventory item. If this item is deleted or updated to reference a - new assetID, the asset can be deleted - - - - Base Class for Inventory Items - - - - of item/folder - - - of parent folder - - - Name of item/folder - - - Item/Folder Owners - - - - Constructor, takes an itemID as a parameter - - The of the item - - - - - - - - - - - - - - - - Generates a number corresponding to the value of the object to support the use of a hash table, - suitable for use in hashing algorithms and data structures such as a hash table - - A Hashcode of all the combined InventoryBase fields - - - - Determine whether the specified object is equal to the current object - - InventoryBase object to compare against - true if objects are the same - - - - Determine whether the specified object is equal to the current object - - InventoryBase object to compare against - true if objects are the same - - - - Convert inventory to OSD - - OSD representation - - - - An Item in Inventory - - - - The of this item - - - The combined of this item - - - The type of item from - - - The type of item from the enum - - - The of the creator of this item - - - A Description of this item - - - The s this item is set to or owned by - - - If true, item is owned by a group - - - The price this item can be purchased for - - - The type of sale from the enum - - - Combined flags from - - - Time and date this inventory item was created, stored as - UTC (Coordinated Universal Time) - - - Used to update the AssetID in requests sent to the server - - - The of the previous owner of the item - - - - Construct a new InventoryItem object - - The of the item - - - - Construct a new InventoryItem object of a specific Type - - The type of item from - of the item - - - - Indicates inventory item is a link - - True if inventory item is a link to another inventory item - - - - - - - - - - - - - - - - Generates a number corresponding to the value of the object to support the use of a hash table. - Suitable for use in hashing algorithms and data structures such as a hash table - - A Hashcode of all the combined InventoryItem fields - - - - Compares an object - - The object to compare - true if comparison object matches - - - - Determine whether the specified object is equal to the current object - - The object to compare against - true if objects are the same - - - - Determine whether the specified object is equal to the current object - - The object to compare against - true if objects are the same - - - - Create InventoryItem from OSD - - OSD Data that makes up InventoryItem - Inventory item created - - - - Convert InventoryItem to OSD - - OSD representation of InventoryItem - - - - InventoryTexture Class representing a graphical image - - - - - - Construct an InventoryTexture object - - A which becomes the - objects AssetUUID - - - - Construct an InventoryTexture object from a serialization stream - - - - - InventorySound Class representing a playable sound - - - - - Construct an InventorySound object - - A which becomes the - objects AssetUUID - - - - Construct an InventorySound object from a serialization stream - - - - - InventoryCallingCard Class, contains information on another avatar - - - - - Construct an InventoryCallingCard object - - A which becomes the - objects AssetUUID - - - - Construct an InventoryCallingCard object from a serialization stream - - - - - InventoryLandmark Class, contains details on a specific location - - - - - Construct an InventoryLandmark object - - A which becomes the - objects AssetUUID - - - - Construct an InventoryLandmark object from a serialization stream - - - - - Landmarks use the InventoryItemFlags struct and will have a flag of 1 set if they have been visited - - - - - InventoryObject Class contains details on a primitive or coalesced set of primitives - - - - - Construct an InventoryObject object - - A which becomes the - objects AssetUUID - - - - Construct an InventoryObject object from a serialization stream - - - - - Gets or sets the upper byte of the Flags value - - - - - Gets or sets the object attachment point, the lower byte of the Flags value - - - - - InventoryNotecard Class, contains details on an encoded text document - - - - - Construct an InventoryNotecard object - - A which becomes the - objects AssetUUID - - - - Construct an InventoryNotecard object from a serialization stream - - - - - InventoryCategory Class - - TODO: Is this even used for anything? - - - - Construct an InventoryCategory object - - A which becomes the - objects AssetUUID - - - - Construct an InventoryCategory object from a serialization stream - - - - - InventoryLSL Class, represents a Linden Scripting Language object - - - - - Construct an InventoryLSL object - - A which becomes the - objects AssetUUID - - - - Construct an InventoryLSL object from a serialization stream - - - - - InventorySnapshot Class, an image taken with the viewer - - - - - Construct an InventorySnapshot object - - A which becomes the - objects AssetUUID - - - - Construct an InventorySnapshot object from a serialization stream - - - - - InventoryAttachment Class, contains details on an attachable object - - - - - Construct an InventoryAttachment object - - A which becomes the - objects AssetUUID - - - - Construct an InventoryAttachment object from a serialization stream - - - - - Get the last AttachmentPoint this object was attached to - - - - - InventoryWearable Class, details on a clothing item or body part - - - - - Construct an InventoryWearable object - - A which becomes the - objects AssetUUID - - - - Construct an InventoryWearable object from a serialization stream - - - - - The , Skin, Shape, Skirt, Etc - - - - - InventoryAnimation Class, A bvh encoded object which animates an avatar - - - - - Construct an InventoryAnimation object - - A which becomes the - objects AssetUUID - - - - Construct an InventoryAnimation object from a serialization stream - - - - - InventoryGesture Class, details on a series of animations, sounds, and actions - - - - - Construct an InventoryGesture object - - A which becomes the - objects AssetUUID - - - - Construct an InventoryGesture object from a serialization stream - - - - - A folder contains s and has certain attributes specific - to itself - - - - The Preferred for a folder. - - - The Version of this folder - - - Number of child items this folder contains. - - - - Constructor - - UUID of the folder - - - - - - - - - - Get Serilization data for this InventoryFolder object - - - - - Construct an InventoryFolder object from a serialization stream - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create InventoryFolder from OSD - - OSD Data that makes up InventoryFolder - Inventory folder created - - - - Convert InventoryItem to OSD - - OSD representation of InventoryItem - - - - Tools for dealing with agents inventory - - - - Used for converting shadow_id to asset_id - - - The event subscribers, null of no subscribers - - - Raises the ItemReceived Event - A ItemReceivedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the FolderUpdated Event - A FolderUpdatedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the InventoryObjectOffered Event - A InventoryObjectOfferedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the TaskItemReceived Event - A TaskItemReceivedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the FindObjectByPath Event - A FindObjectByPathEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the TaskInventoryReply Event - A TaskInventoryReplyEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the SaveAssetToInventory Event - A SaveAssetToInventoryEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the ScriptRunningReply Event - A ScriptRunningReplyEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - Partial mapping of AssetTypes to folder names - - - - Default constructor - - Reference to the GridClient object - - - - Fetch an inventory item from the dataserver - - The items - The item Owners - a integer representing the number of milliseconds to wait for results - An object on success, or null if no item was found - Items will also be sent to the event - - - - Request A single inventory item - - The items - The item Owners - - - - - Request inventory items - - Inventory items to request - Owners of the inventory items - - - - - Request inventory items via Capabilities - - Inventory items to request - Owners of the inventory items - - - - - Get contents of a folder - - The of the folder to search - The of the folders owner - true to retrieve folders - true to retrieve items - sort order to return results in - a integer representing the number of milliseconds to wait for results - A list of inventory items matching search criteria within folder - - InventoryFolder.DescendentCount will only be accurate if both folders and items are - requested - - - - Request the contents of an inventory folder - - The folder to search - The folder owners - true to return s contained in folder - true to return s containd in folder - the sort order to return items in - - - - - Request the contents of an inventory folder using HTTP capabilities - - The folder to search - The folder owners - true to return s contained in folder - true to return s containd in folder - the sort order to return items in - - - - - Returns the UUID of the folder (category) that defaults to - containing 'type'. The folder is not necessarily only for that - type - - This will return the root folder if one does not exist - - The UUID of the desired folder if found, the UUID of the RootFolder - if not found, or UUID.Zero on failure - - - - Find an object in inventory using a specific path to search - - The folder to begin the search in - The object owners - A string path to search - milliseconds to wait for a reply - Found items or if - timeout occurs or item is not found - - - - Find inventory items by path - - The folder to begin the search in - The object owners - A string path to search, folders/objects separated by a '/' - Results are sent to the event - - - - Search inventory Store object for an item or folder - - The folder to begin the search in - An array which creates a path to search - Number of levels below baseFolder to conduct searches - if True, will stop searching after first match is found - A list of inventory items found - - - - Move an inventory item or folder to a new location - - The item or folder to move - The to move item or folder to - - - - Move an inventory item or folder to a new location and change its name - - The item or folder to move - The to move item or folder to - The name to change the item or folder to - - - - Move and rename a folder - - The source folders - The destination folders - The name to change the folder to - - - - Update folder properties - - of the folder to update - Sets folder's parent to - Folder name - Folder type - - - - Move a folder - - The source folders - The destination folders - - - - Move multiple folders, the keys in the Dictionary parameter, - to a new parents, the value of that folder's key. - - A Dictionary containing the - of the source as the key, and the - of the destination as the value - - - - Move an inventory item to a new folder - - The of the source item to move - The of the destination folder - - - - Move and rename an inventory item - - The of the source item to move - The of the destination folder - The name to change the folder to - - - - Move multiple inventory items to new locations - - A Dictionary containing the - of the source item as the key, and the - of the destination folder as the value - - - - Remove descendants of a folder - - The of the folder - - - - Remove a single item from inventory - - The of the inventory item to remove - - - - Remove a folder from inventory - - The of the folder to remove - - - - Remove multiple items or folders from inventory - - A List containing the s of items to remove - A List containing the s of the folders to remove - - - - Empty the Lost and Found folder - - - - - Empty the Trash folder - - - - - - - - - - - Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. - - - - - - - - - - - - - Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. - - - - - - - - Creates a new inventory folder - - ID of the folder to put this folder in - Name of the folder to create - The UUID of the newly created folder - - - - Creates a new inventory folder - - ID of the folder to put this folder in - Name of the folder to create - Sets this folder as the default folder - for new assets of the specified type. Use AssetType.Unknown - to create a normal folder, otherwise it will likely create a - duplicate of an existing folder type - The UUID of the newly created folder - If you specify a preferred type of AsseType.Folder - it will create a new root folder which may likely cause all sorts - of strange problems - - - - Create an inventory item and upload asset data - - Asset data - Inventory item name - Inventory item description - Asset type - Inventory type - Put newly created inventory in this folder - Delegate that will receive feedback on success or failure - - - - Create an inventory item and upload asset data - - Asset data - Inventory item name - Inventory item description - Asset type - Inventory type - Put newly created inventory in this folder - Permission of the newly created item - (EveryoneMask, GroupMask, and NextOwnerMask of Permissions struct are supported) - Delegate that will receive feedback on success or failure - - - - Creates inventory link to another inventory item or folder - - Put newly created link in folder with this UUID - Inventory item or folder - Method to call upon creation of the link - - - - Creates inventory link to another inventory item - - Put newly created link in folder with this UUID - Original inventory item - Method to call upon creation of the link - - - - Creates inventory link to another inventory folder - - Put newly created link in folder with this UUID - Original inventory folder - Method to call upon creation of the link - - - - Creates inventory link to another inventory item or folder - - Put newly created link in folder with this UUID - Original item's UUID - Name - Description - Asset Type - Inventory Type - Transaction UUID - Method to call upon creation of the link - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Request a copy of an asset embedded within a notecard - - Usually UUID.Zero for copying an asset from a notecard - UUID of the notecard to request an asset from - Target folder for asset to go to in your inventory - UUID of the embedded asset - callback to run when item is copied to inventory - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Save changes to notecard embedded in object contents - - Encoded notecard asset data - Notecard UUID - Object's UUID - Called upon finish of the upload with status information - - - - Upload new gesture asset for an inventory gesture item - - Encoded gesture asset - Gesture inventory UUID - Callback whick will be called when upload is complete - - - - Update an existing script in an agents Inventory - - A byte[] array containing the encoded scripts contents - the itemID of the script - if true, sets the script content to run on the mono interpreter - - - - - Update an existing script in an task Inventory - - A byte[] array containing the encoded scripts contents - the itemID of the script - UUID of the prim containting the script - if true, sets the script content to run on the mono interpreter - if true, sets the script to running - - - - - Rez an object from inventory - - Simulator to place object in - Rotation of the object when rezzed - Vector of where to place object - InventoryItem object containing item details - - - - Rez an object from inventory - - Simulator to place object in - Rotation of the object when rezzed - Vector of where to place object - InventoryItem object containing item details - UUID of group to own the object - - - - Rez an object from inventory - - Simulator to place object in - Rotation of the object when rezzed - Vector of where to place object - InventoryItem object containing item details - UUID of group to own the object - User defined queryID to correlate replies - If set to true, the CreateSelected flag - will be set on the rezzed object - - - - Rez an object from inventory - - Simulator to place object in - TaskID object when rezzed - Rotation of the object when rezzed - Vector of where to place object - InventoryItem object containing item details - UUID of group to own the object - User defined queryID to correlate replies - If set to true, the CreateSelected flag - will be set on the rezzed object - - - - DeRez an object from the simulator to the agents Objects folder in the agents Inventory - - The simulator Local ID of the object - If objectLocalID is a child primitive in a linkset, the entire linkset will be derezzed - - - - DeRez an object from the simulator and return to inventory - - The simulator Local ID of the object - The type of destination from the enum - The destination inventory folders -or- - if DeRezzing object to a tasks Inventory, the Tasks - The transaction ID for this request which - can be used to correlate this request with other packets - If objectLocalID is a child primitive in a linkset, the entire linkset will be derezzed - - - - Rez an item from inventory to its previous simulator location - - - - - - - - - Give an inventory item to another avatar - - The of the item to give - The name of the item - The type of the item from the enum - The of the recipient - true to generate a beameffect during transfer - - - - Give an inventory Folder with contents to another avatar - - The of the Folder to give - The name of the folder - The type of the item from the enum - The of the recipient - true to generate a beameffect during transfer - - - - Copy or move an from agent inventory to a task (primitive) inventory - - The target object - The item to copy or move from inventory - - For items with copy permissions a copy of the item is placed in the tasks inventory, - for no-copy items the object is moved to the tasks inventory - - - - Retrieve a listing of the items contained in a task (Primitive) - - The tasks - The tasks simulator local ID - milliseconds to wait for reply from simulator - A list containing the inventory items inside the task or null - if a timeout occurs - This request blocks until the response from the simulator arrives - or timeoutMS is exceeded - - - - Request the contents of a tasks (primitives) inventory from the - current simulator - - The LocalID of the object - - - - - Request the contents of a tasks (primitives) inventory - - The simulator Local ID of the object - A reference to the simulator object that contains the object - - - - - Move an item from a tasks (Primitive) inventory to the specified folder in the avatars inventory - - LocalID of the object in the simulator - UUID of the task item to move - The ID of the destination folder in this agents inventory - Simulator Object - Raises the event - - - - Remove an item from an objects (Prim) Inventory - - LocalID of the object in the simulator - UUID of the task item to remove - Simulator Object - You can confirm the removal by comparing the tasks inventory serial before and after the - request with the request combined with - the event - - - - Copy an InventoryScript item from the Agents Inventory into a primitives task inventory - - An unsigned integer representing a primitive being simulated - An which represents a script object from the agents inventory - true to set the scripts running state to enabled - A Unique Transaction ID - - The following example shows the basic steps necessary to copy a script from the agents inventory into a tasks inventory - and assumes the script exists in the agents inventory. - - uint primID = 95899503; // Fake prim ID - UUID scriptID = UUID.Parse("92a7fe8a-e949-dd39-a8d8-1681d8673232"); // Fake Script UUID in Inventory - - Client.Inventory.FolderContents(Client.Inventory.FindFolderForType(AssetType.LSLText), Client.Self.AgentID, - false, true, InventorySortOrder.ByName, 10000); - - Client.Inventory.RezScript(primID, (InventoryItem)Client.Inventory.Store[scriptID]); - - - - - - Request the running status of a script contained in a task (primitive) inventory - - The ID of the primitive containing the script - The ID of the script - The event can be used to obtain the results of the - request - - - - - Send a request to set the running state of a script contained in a task (primitive) inventory - - The ID of the primitive containing the script - The ID of the script - true to set the script running, false to stop a running script - To verify the change you can use the method combined - with the event - - - - Create a CRC from an InventoryItem - - The source InventoryItem - A uint representing the source InventoryItem as a CRC - - - - Reverses a cheesy XORing with a fixed UUID to convert a shadow_id to an asset_id - - Obfuscated shadow_id value - Deobfuscated asset_id value - - - - Does a cheesy XORing with a fixed UUID to convert an asset_id to a shadow_id - - asset_id value to obfuscate - Obfuscated shadow_id value - - - - Wrapper for creating a new object - - The type of item from the enum - The of the newly created object - An object with the type and id passed - - - - Parse the results of a RequestTaskInventory() response - - A string which contains the data from the task reply - A List containing the items contained within the tasks inventory - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - - UpdateCreateInventoryItem packets are received when a new inventory item - is created. This may occur when an object that's rezzed in world is - taken into inventory, when an item is created using the CreateInventoryItem - packet, or when an object is purchased - - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - an inventory object sent by another avatar or primitive - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - - Get this agents Inventory data - - - - - Callback for inventory item creation finishing - - Whether the request to create an inventory - item succeeded or not - Inventory item being created. If success is - false this will be null - - - - Callback for an inventory item being create from an uploaded asset - - true if inventory item creation was successful - - - - - - - - - - - - - Reply received when uploading an inventory asset - - Has upload been successful - Error message if upload failed - Inventory asset UUID - New asset UUID - - - - Delegate that is invoked when script upload is completed - - Has upload succeded (note, there still might be compile errors) - Upload status message - Is compilation successful - If compilation failed, list of error messages, null on compilation success - Script inventory UUID - Script's new asset UUID - - - Set to true to accept offer, false to decline it - - - The folder to accept the inventory into, if null default folder for will be used - - - - Callback when an inventory object is accepted and received from a - task inventory. This is the callback in which you actually get - the ItemID, as in ObjectOfferedCallback it is null when received - from a task. - - - - - - - - - - - - - - - - De-serialization constructor for the InventoryNode Class - - - - - Serialization handler for the InventoryNode Class - - - - - De-serialization handler for the InventoryNode Class - - - - - - - - - - - - - User data - - - - - - - - - - - - - For inventory folder nodes specifies weather the folder needs to be - refreshed from the server - - - - - Singleton logging class for the entire library - - - - log4net logging engine - - - - Default constructor - - - - - Send a log message to the logging engine - - The log message - The severity of the log entry - - - - Send a log message to the logging engine - - The log message - The severity of the log entry - Instance of the client - - - - Send a log message to the logging engine - - The log message - The severity of the log entry - Exception that was raised - - - - Send a log message to the logging engine - - The log message - The severity of the log entry - Instance of the client - Exception that was raised - - - - If the library is compiled with DEBUG defined, an event will be - fired if an OnLogMessage handler is registered and the - message will be sent to the logging engine - - The message to log at the DEBUG level to the - current logging engine - - - - If the library is compiled with DEBUG defined and - GridClient.Settings.DEBUG is true, an event will be - fired if an OnLogMessage handler is registered and the - message will be sent to the logging engine - - The message to log at the DEBUG level to the - current logging engine - Instance of the client - - - Triggered whenever a message is logged. If this is left - null, log messages will go to the console - - - - Callback used for client apps to receive log messages from - the library - - Data being logged - The severity of the log entry from - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Status of the last application run. - Used for error reporting to the grid login service for statistical purposes. - - - - Application exited normally - - - Application froze - - - Application detected error and exited abnormally - - - Other crash - - - Application froze during logout - - - Application crashed during logout - - - - Login Request Parameters - - - - The URL of the Login Server - - - The number of milliseconds to wait before a login is considered - failed due to timeout - - - The request method - login_to_simulator is currently the only supported method - - - The Agents First name - - - The Agents Last name - - - A md5 hashed password - plaintext password will be automatically hashed - - - The agents starting location once logged in - Either "last", "home", or a string encoded URI - containing the simulator name and x/y/z coordinates e.g: uri:hooper&128&152&17 - - - A string containing the client software channel information - Second Life Release - - - The client software version information - The official viewer uses: Second Life Release n.n.n.n - where n is replaced with the current version of the viewer - - - A string containing the platform information the agent is running on - - - A string hash of the network cards Mac Address - - - Unknown or deprecated - - - A string hash of the first disk drives ID used to identify this clients uniqueness - - - A string containing the viewers Software, this is not directly sent to the login server but - instead is used to generate the Version string - - - A string representing the software creator. This is not directly sent to the login server but - is used by the library to generate the Version information - - - If true, this agent agrees to the Terms of Service of the grid its connecting to - - - Unknown - - - Status of the last application run sent to the grid login server for statistical purposes - - - An array of string sent to the login server to enable various options - - - A randomly generated ID to distinguish between login attempts. This value is only used - internally in the library and is never sent over the wire - - - - Default constuctor, initializes sane default values - - - - - Instantiates new LoginParams object and fills in the values - - Instance of GridClient to read settings from - Login first name - Login last name - Password - Login channnel (application name) - Client version, should be application name + version number - - - - Instantiates new LoginParams object and fills in the values - - Instance of GridClient to read settings from - Login first name - Login last name - Password - Login channnel (application name) - Client version, should be application name + version number - URI of the login server - - - - The decoded data returned from the login server after a successful login - - - - true, false, indeterminate - - - Login message of the day - - - M or PG, also agent_region_access and agent_access_max - - - - Parse LLSD Login Reply Data - - An - contaning the login response data - XML-RPC logins do not require this as XML-RPC.NET - automatically populates the struct properly using attributes - - - - Login Routines - - - NetworkManager is responsible for managing the network layer of - OpenMetaverse. It tracks all the server connections, serializes - outgoing traffic and deserializes incoming traffic, and provides - instances of delegates for network-related events. - - - - The event subscribers, null of no subscribers - - - Raises the LoginProgress Event - A LoginProgressEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - Seed CAPS URL returned from the login server - - - Maximum number of groups an agent can belong to, -1 for unlimited - - - Server side baking service URL - - - Parsed login response data - - - A list of packets obtained during the login process which - networkmanager will log but not process - - - - Generate sane default values for a login request - - Account first name - Account last name - Account password - Client application name (channel) - Client application name + version - A populated struct containing - sane defaults - - - - Simplified login that takes the most common and required fields - - Account first name - Account last name - Account password - Client application name (channel) - Client application name + version - Whether the login was successful or not. On failure the - LoginErrorKey string will contain the error code and LoginMessage - will contain a description of the error - - - - Simplified login that takes the most common fields along with a - starting location URI, and can accept an MD5 string instead of a - plaintext password - - Account first name - Account last name - Account password or MD5 hash of the password - such as $1$1682a1e45e9f957dcdf0bb56eb43319c - Client application name (channel) - Starting location URI that can be built with - StartLocation() - Client application name + version - Whether the login was successful or not. On failure the - LoginErrorKey string will contain the error code and LoginMessage - will contain a description of the error - - - - Login that takes a struct of all the values that will be passed to - the login server - - The values that will be passed to the login - server, all fields must be set even if they are String.Empty - Whether the login was successful or not. On failure the - LoginErrorKey string will contain the error code and LoginMessage - will contain a description of the error - - - - Build a start location URI for passing to the Login function - - Name of the simulator to start in - X coordinate to start at - Y coordinate to start at - Z coordinate to start at - String with a URI that can be used to login to a specified - location - - - - LoginParams and the initial login XmlRpcRequest were made on a remote machine. - This method now initializes libomv with the results. - - - - - Handles response from XML-RPC login replies - - - - - Handles response from XML-RPC login replies with already parsed LoginResponseData - - - - - Handle response from LLSD login replies - - - - - - - - Get current OS - - Either "Win" or "Linux" - - - - Get clients default Mac Address - - A string containing the first found Mac Address - - - The event subscribers, null of no subscribers - - - Raises the PacketSent Event - A PacketSentEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the LoggedOut Event - A LoggedOutEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the SimConnecting Event - A SimConnectingEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the SimConnected Event - A SimConnectedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the SimDisconnected Event - A SimDisconnectedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the Disconnected Event - A DisconnectedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the SimChanged Event - A SimChangedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the EventQueueRunning Event - A EventQueueRunningEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - All of the simulators we are currently connected to - - - Handlers for incoming capability events - - - Handlers for incoming packets - - - Incoming packets that are awaiting handling - - - Outgoing packets that are awaiting handling - - - - Default constructor - - Reference to the GridClient object - - - - Register an event handler for a packet. This is a low level event - interface and should only be used if you are doing something not - supported in the library - - Packet type to trigger events for - Callback to fire when a packet of this type - is received - - - - Register an event handler for a packet. This is a low level event - interface and should only be used if you are doing something not - supported in the library - - Packet type to trigger events for - Callback to fire when a packet of this type - is received - True if the callback should be ran - asynchronously. Only set this to false (synchronous for callbacks - that will always complete quickly) - If any callback for a packet type is marked as - asynchronous, all callbacks for that packet type will be fired - asynchronously - - - - Unregister an event handler for a packet. This is a low level event - interface and should only be used if you are doing something not - supported in the library - - Packet type this callback is registered with - Callback to stop firing events for - - - - Register a CAPS event handler. This is a low level event interface - and should only be used if you are doing something not supported in - the library - - Name of the CAPS event to register a handler for - Callback to fire when a CAPS event is received - - - - Unregister a CAPS event handler. This is a low level event interface - and should only be used if you are doing something not supported in - the library - - Name of the CAPS event this callback is - registered with - Callback to stop firing events for - - - - Send a packet to the simulator the avatar is currently occupying - - Packet to send - - - - Send a packet to a specified simulator - - Packet to send - Simulator to send the packet to - - - - Connect to a simulator - - IP address to connect to - Port to connect to - Handle for this simulator, to identify its - location in the grid - Whether to set CurrentSim to this new - connection, use this if the avatar is moving in to this simulator - URL of the capabilities server to use for - this sim connection - A Simulator object on success, otherwise null - - - - Connect to a simulator - - IP address and port to connect to - Handle for this simulator, to identify its - location in the grid - Whether to set CurrentSim to this new - connection, use this if the avatar is moving in to this simulator - URL of the capabilities server to use for - this sim connection - A Simulator object on success, otherwise null - - - - Initiate a blocking logout request. This will return when the logout - handshake has completed or when Settings.LOGOUT_TIMEOUT - has expired and the network layer is manually shut down - - - - - Initiate the logout process. Check if logout succeeded with the - OnLogoutReply event, and if this does not fire the - Shutdown() function needs to be manually called - - - - - Close a connection to the given simulator - - - - - - - Shutdown will disconnect all the sims except for the current sim - first, and then kill the connection to CurrentSim. This should only - be called if the logout process times out on RequestLogout - - Type of shutdown - - - - Shutdown will disconnect all the sims except for the current sim - first, and then kill the connection to CurrentSim. This should only - be called if the logout process times out on RequestLogout - - Type of shutdown - Shutdown message - - - - Searches through the list of currently connected simulators to find - one attached to the given IPEndPoint - - IPEndPoint of the Simulator to search for - A Simulator reference on success, otherwise null - - - - Fire an event when an event queue connects for capabilities - - Simulator the event queue is attached to - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Raised when the simulator sends us data containing - ... - - - Called when a reply is received from the login server, the - login sequence will block until this event returns - - - Current state of logging in - - - Upon login failure, contains a short string key for the - type of login error that occurred - - - The raw XML-RPC reply from the login server, exactly as it - was received (minus the HTTP header) - - - During login this contains a descriptive version of - LoginStatusCode. After a successful login this will contain the - message of the day, and after a failed login a descriptive error - message will be returned - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Unique identifier associated with our connections to - simulators - - - The simulator that the logged in avatar is currently - occupying - - - Shows whether the network layer is logged in to the - grid or not - - - Number of packets in the incoming queue - - - Number of packets in the outgoing queue - - - - - - - - - - - - - - Explains why a simulator or the grid disconnected from us - - - - The client requested the logout or simulator disconnect - - - The server notified us that it is disconnecting - - - Either a socket was closed or network traffic timed out - - - The last active simulator shut down - - - - Holds a simulator reference and a decoded packet, these structs are put in - the packet inbox for event handling - - - - Reference to the simulator that this packet came from - - - Packet that needs to be processed - - - - Holds a simulator reference and a serialized packet, these structs are put in - the packet outbox for sending - - - - Reference to the simulator this packet is destined for - - - Packet that needs to be sent - - - Sequence number of the wrapped packet - - - Number of times this packet has been resent - - - Environment.TickCount when this packet was last sent over the wire - - - Type of the packet - - - - A Name Value pair with additional settings, used in the protocol - primarily to transmit avatar names and active group in object packets - - - - - - - - - - - - - - - - - - - - Constructor that takes all the fields as parameters - - - - - - - - - - Constructor that takes a single line from a NameValue field - - - - - Type of the value - - - Unknown - - - String value - - - - - - - - - - - - - - - Deprecated - - - String value, but designated as an asset - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No report - - - Unknown report type - - - Bug report - - - Complaint report - - - Customer service report - - - - Bitflag field for ObjectUpdateCompressed data blocks, describing - which options are present for each object - - - - Unknown - - - Whether the object has a TreeSpecies - - - Whether the object has floating text ala llSetText - - - Whether the object has an active particle system - - - Whether the object has sound attached to it - - - Whether the object is attached to a root object or not - - - Whether the object has texture animation settings - - - Whether the object has an angular velocity - - - Whether the object has a name value pairs string - - - Whether the object has a Media URL set - - - - Specific Flags for MultipleObjectUpdate requests - - - - None - - - Change position of prims - - - Change rotation of prims - - - Change size of prims - - - Perform operation on link set - - - Scale prims uniformly, same as selecing ctrl+shift in the - viewer. Used in conjunction with Scale - - - - Special values in PayPriceReply. If the price is not one of these - literal value of the price should be use - - - - - Indicates that this pay option should be hidden - - - - - Indicates that this pay option should have the default value - - - - - Contains the variables sent in an object update packet for objects. - Used to track position and movement of prims and avatars - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Handles all network traffic related to prims and avatar positions and - movement. - - - - The event subscribers, null of no subscribers - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the ObjectProperties Event - A ObjectPropertiesEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the ObjectPropertiesUpdated Event - A ObjectPropertiesUpdatedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the ObjectPropertiesFamily Event - A ObjectPropertiesFamilyEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the AvatarUpdate Event - A AvatarUpdateEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the ObjectDataBlockUpdate Event - A ObjectDataBlockUpdateEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the KillObject Event - A KillObjectEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the KillObjects Event - A KillObjectsEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the AvatarSitChanged Event - A AvatarSitChangedEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the PayPriceReply Event - A PayPriceReplyEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the PhysicsProperties Event - A PhysicsPropertiesEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - Reference to the GridClient object - - - Does periodic dead reckoning calculation to convert - velocity and acceleration to new positions for objects - - - - Construct a new instance of the ObjectManager class - - A reference to the instance - - - - Request information for a single object from a - you are currently connected to - - The the object is located - The Local ID of the object - - - - Request information for multiple objects contained in - the same simulator - - The the objects are located - An array containing the Local IDs of the objects - - - - Attempt to purchase an original object, a copy, or the contents of - an object - - The the object is located - The Local ID of the object - Whether the original, a copy, or the object - contents are on sale. This is used for verification, if the this - sale type is not valid for the object the purchase will fail - Price of the object. This is used for - verification, if it does not match the actual price the purchase - will fail - Group ID that will be associated with the new - purchase - Inventory folder UUID where the object or objects - purchased should be placed - - - BuyObject(Client.Network.CurrentSim, 500, SaleType.Copy, - 100, UUID.Zero, Client.Self.InventoryRootFolderUUID); - - - - - - Request prices that should be displayed in pay dialog. This will triggger the simulator - to send us back a PayPriceReply which can be handled by OnPayPriceReply event - - The the object is located - The ID of the object - The result is raised in the event - - - - Select a single object. This will cause the to send us - an which will raise the event - - The the object is located - The Local ID of the object - - - - - Select a single object. This will cause the to send us - an which will raise the event - - The the object is located - The Local ID of the object - if true, a call to is - made immediately following the request - - - - - Select multiple objects. This will cause the to send us - an which will raise the event - - The the objects are located - An array containing the Local IDs of the objects - Should objects be deselected immediately after selection - - - - - Select multiple objects. This will cause the to send us - an which will raise the event - - The the objects are located - An array containing the Local IDs of the objects - - - - - Update the properties of an object - - The the object is located - The Local ID of the object - true to turn the objects physical property on - true to turn the objects temporary property on - true to turn the objects phantom property on - true to turn the objects cast shadows property on - - - - Update the properties of an object - - The the object is located - The Local ID of the object - true to turn the objects physical property on - true to turn the objects temporary property on - true to turn the objects phantom property on - true to turn the objects cast shadows property on - Type of the represetnation prim will have in the physics engine - Density - normal value 1000 - Friction - normal value 0.6 - Restitution - standard value 0.5 - Gravity multiplier - standar value 1.0 - - - - Sets the sale properties of a single object - - The the object is located - The Local ID of the object - One of the options from the enum - The price of the object - - - - Sets the sale properties of multiple objects - - The the objects are located - An array containing the Local IDs of the objects - One of the options from the enum - The price of the object - - - - Deselect a single object - - The the object is located - The Local ID of the object - - - - Deselect multiple objects. - - The the objects are located - An array containing the Local IDs of the objects - - - - Perform a click action on an object - - The the object is located - The Local ID of the object - - - - Perform a click action (Grab) on a single object - - The the object is located - The Local ID of the object - The texture coordinates to touch - The surface coordinates to touch - The face of the position to touch - The region coordinates of the position to touch - The surface normal of the position to touch (A normal is a vector perpindicular to the surface) - The surface binormal of the position to touch (A binormal is a vector tangen to the surface - pointing along the U direction of the tangent space - - - - Create (rez) a new prim object in a simulator - - A reference to the object to place the object in - Data describing the prim object to rez - Group ID that this prim will be set to, or UUID.Zero if you - do not want the object to be associated with a specific group - An approximation of the position at which to rez the prim - Scale vector to size this prim - Rotation quaternion to rotate this prim - Due to the way client prim rezzing is done on the server, - the requested position for an object is only close to where the prim - actually ends up. If you desire exact placement you'll need to - follow up by moving the object after it has been created. This - function will not set textures, light and flexible data, or other - extended primitive properties - - - - Create (rez) a new prim object in a simulator - - A reference to the object to place the object in - Data describing the prim object to rez - Group ID that this prim will be set to, or UUID.Zero if you - do not want the object to be associated with a specific group - An approximation of the position at which to rez the prim - Scale vector to size this prim - Rotation quaternion to rotate this prim - Specify the - Due to the way client prim rezzing is done on the server, - the requested position for an object is only close to where the prim - actually ends up. If you desire exact placement you'll need to - follow up by moving the object after it has been created. This - function will not set textures, light and flexible data, or other - extended primitive properties - - - - Rez a Linden tree - - A reference to the object where the object resides - The size of the tree - The rotation of the tree - The position of the tree - The Type of tree - The of the group to set the tree to, - or UUID.Zero if no group is to be set - true to use the "new" Linden trees, false to use the old - - - - Rez grass and ground cover - - A reference to the object where the object resides - The size of the grass - The rotation of the grass - The position of the grass - The type of grass from the enum - The of the group to set the tree to, - or UUID.Zero if no group is to be set - - - - Set the textures to apply to the faces of an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The texture data to apply - - - - Set the textures to apply to the faces of an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The texture data to apply - A media URL (not used) - - - - Set the Light data on an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - A object containing the data to set - - - - Set the flexible data on an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - A object containing the data to set - - - - Set the sculptie texture and data on an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - A object containing the data to set - - - - Unset additional primitive parameters on an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The extra parameters to set - - - - Link multiple prims into a linkset - - A reference to the object where the objects reside - An array which contains the IDs of the objects to link - The last object in the array will be the root object of the linkset TODO: Is this true? - - - - Delink/Unlink multiple prims from a linkset - - A reference to the object where the objects reside - An array which contains the IDs of the objects to delink - - - - Change the rotation of an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The new rotation of the object - - - - Set the name of an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - A string containing the new name of the object - - - - Set the name of multiple objects - - A reference to the object where the objects reside - An array which contains the IDs of the objects to change the name of - An array which contains the new names of the objects - - - - Set the description of an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - A string containing the new description of the object - - - - Set the descriptions of multiple objects - - A reference to the object where the objects reside - An array which contains the IDs of the objects to change the description of - An array which contains the new descriptions of the objects - - - - Attach an object to this avatar - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The point on the avatar the object will be attached - The rotation of the attached object - - - - Drop an attached object from this avatar - - A reference to the - object where the objects reside. This will always be the simulator the avatar is currently in - - The object's ID which is local to the simulator the object is in - - - - Detach an object from yourself - - A reference to the - object where the objects reside - - This will always be the simulator the avatar is currently in - - An array which contains the IDs of the objects to detach - - - - Change the position of an object, Will change position of entire linkset - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The new position of the object - - - - Change the position of an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The new position of the object - if true, will change position of (this) child prim only, not entire linkset - - - - Change the Scale (size) of an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The new scale of the object - If true, will change scale of this prim only, not entire linkset - True to resize prims uniformly - - - - Change the Rotation of an object that is either a child or a whole linkset - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The new scale of the object - If true, will change rotation of this prim only, not entire linkset - - - - Send a Multiple Object Update packet to change the size, scale or rotation of a primitive - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The new rotation, size, or position of the target object - The flags from the Enum - - - - Deed an object (prim) to a group, Object must be shared with group which - can be accomplished with SetPermissions() - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The of the group to deed the object to - - - - Deed multiple objects (prims) to a group, Objects must be shared with group which - can be accomplished with SetPermissions() - - A reference to the object where the object resides - An array which contains the IDs of the objects to deed - The of the group to deed the object to - - - - Set the permissions on multiple objects - - A reference to the object where the objects reside - An array which contains the IDs of the objects to set the permissions on - The new Who mask to set - Which permission to modify - The new state of permission - - - - Request additional properties for an object - - A reference to the object where the object resides - - - - - Request additional properties for an object - - A reference to the object where the object resides - Absolute UUID of the object - Whether to require server acknowledgement of this request - - - - Set the ownership of a list of objects to the specified group - - A reference to the object where the objects reside - An array which contains the IDs of the objects to set the group id on - The Groups ID - - - - Update current URL of the previously set prim media - - UUID of the prim - Set current URL to this - Prim face number - Simulator in which prim is located - - - - Set object media - - UUID of the prim - Array the length of prims number of faces. Null on face indexes where there is - no media, on faces which contain the media - Simulatior in which prim is located - - - - Retrieve information about object media - - UUID of the primitive - Simulator where prim is located - Call this callback when done - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - - A terse object update, used when a transformation matrix or - velocity/acceleration for an object changes but nothing else - (scale/position/rotation/acceleration/velocity) - - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - - - - - - - - - - Setup construction data for a basic primitive shape - - Primitive shape to construct - Construction data that can be plugged into a - - - - - - - - - - - - - - - - - - - - Set the Shape data of an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - Data describing the prim shape - - - - Set the Material data of an object - - A reference to the object where the object resides - The objects ID which is local to the simulator the object is in - The new material of the object - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Raised when the simulator sends us data containing - A , Foliage or Attachment - - - - - Raised when the simulator sends us data containing - additional information - - - - - Raised when the simulator sends us data containing - Primitive.ObjectProperties for an object we are currently tracking - - - Raised when the simulator sends us data containing - additional and details - - - - Raised when the simulator sends us data containing - updated information for an - - - Raised when the simulator sends us data containing - and movement changes - - - Raised when the simulator sends us data containing - updates to an Objects DataBlock - - - Raised when the simulator informs us an - or is no longer within view - - - Raised when the simulator informs us when a group of - or is no longer within view - - - Raised when the simulator sends us data containing - updated sit information for our - - - Raised when the simulator sends us data containing - purchase price information for a - - - Raised when the simulator sends us data containing - additional information - - - - - - Callback for getting object media data via CAP - - Indicates if the operation was succesfull - Object media version string - Array indexed on prim face of media entry data - - - Provides data for the event - The event occurs when the simulator sends - an containing a Primitive, Foliage or Attachment data - Note 1: The event will not be raised when the object is an Avatar - Note 2: It is possible for the to be - raised twice for the same object if for example the primitive moved to a new simulator, then returned to the current simulator or - if an Avatar crosses the border into a new simulator and returns to the current simulator - - - The following code example uses the , , and - properties to display new Primitives and Attachments on the window. - - // Subscribe to the event that gives us prim and foliage information - Client.Objects.ObjectUpdate += Objects_ObjectUpdate; - - - private void Objects_ObjectUpdate(object sender, PrimEventArgs e) - { - Console.WriteLine("Primitive {0} {1} in {2} is an attachment {3}", e.Prim.ID, e.Prim.LocalID, e.Simulator.Name, e.IsAttachment); - } - - - - - - - - - Construct a new instance of the PrimEventArgs class - - The simulator the object originated from - The Primitive - The simulator time dilation - The prim was not in the dictionary before this update - true if the primitive represents an attachment to an agent - - - Get the simulator the originated from - - - Get the details - - - true if the did not exist in the dictionary before this update (always true if object tracking has been disabled) - - - true if the is attached to an - - - Get the simulator Time Dilation - - - Provides data for the event - The event occurs when the simulator sends - an containing Avatar data - Note 1: The event will not be raised when the object is an Avatar - Note 2: It is possible for the to be - raised twice for the same avatar if for example the avatar moved to a new simulator, then returned to the current simulator - - - The following code example uses the property to make a request for the top picks - using the method in the class to display the names - of our own agents picks listings on the window. - - // subscribe to the AvatarUpdate event to get our information - Client.Objects.AvatarUpdate += Objects_AvatarUpdate; - Client.Avatars.AvatarPicksReply += Avatars_AvatarPicksReply; - - private void Objects_AvatarUpdate(object sender, AvatarUpdateEventArgs e) - { - // we only want our own data - if (e.Avatar.LocalID == Client.Self.LocalID) - { - // Unsubscribe from the avatar update event to prevent a loop - // where we continually request the picks every time we get an update for ourselves - Client.Objects.AvatarUpdate -= Objects_AvatarUpdate; - // make the top picks request through AvatarManager - Client.Avatars.RequestAvatarPicks(e.Avatar.ID); - } - } - - private void Avatars_AvatarPicksReply(object sender, AvatarPicksReplyEventArgs e) - { - // we'll unsubscribe from the AvatarPicksReply event since we now have the data - // we were looking for - Client.Avatars.AvatarPicksReply -= Avatars_AvatarPicksReply; - // loop through the dictionary and extract the names of the top picks from our profile - foreach (var pickName in e.Picks.Values) - { - Console.WriteLine(pickName); - } - } - - - - - - - - Construct a new instance of the AvatarUpdateEventArgs class - - The simulator the packet originated from - The data - The simulator time dilation - The avatar was not in the dictionary before this update - - - Get the simulator the object originated from - - - Get the data - - - Get the simulator time dilation - - - true if the did not exist in the dictionary before this update (always true if avatar tracking has been disabled) - - - Provides additional primitive data for the event - The event occurs when the simulator sends - an containing additional details for a Primitive, Foliage data or Attachment data - The event is also raised when a request is - made. - - - The following code example uses the , and - - properties to display new attachments and send a request for additional properties containing the name of the - attachment then display it on the window. - - // Subscribe to the event that provides additional primitive details - Client.Objects.ObjectProperties += Objects_ObjectProperties; - - // handle the properties data that arrives - private void Objects_ObjectProperties(object sender, ObjectPropertiesEventArgs e) - { - Console.WriteLine("Primitive Properties: {0} Name is {1}", e.Properties.ObjectID, e.Properties.Name); - } - - - - - - Construct a new instance of the ObjectPropertiesEventArgs class - - The simulator the object is located - The primitive Properties - - - Get the simulator the object is located - - - Get the primitive properties - - - Provides additional primitive data for the event - The event occurs when the simulator sends - an containing additional details for a Primitive or Foliage data that is currently - being tracked in the dictionary - The event is also raised when a request is - made and is enabled - - - - - Construct a new instance of the ObjectPropertiesUpdatedEvenrArgs class - - The simulator the object is located - The Primitive - The primitive Properties - - - Get the primitive details - - - Provides additional primitive data, permissions and sale info for the event - The event occurs when the simulator sends - an containing additional details for a Primitive, Foliage data or Attachment. This includes - Permissions, Sale info, and other basic details on an object - The event is also raised when a request is - made, the viewer equivalent is hovering the mouse cursor over an object - - - - Get the simulator the object is located - - - - - - - - - Provides primitive data containing updated location, velocity, rotation, textures for the event - The event occurs when the simulator sends updated location, velocity, rotation, etc - - - - Get the simulator the object is located - - - Get the primitive details - - - - - - - - - - - - - - Get the simulator the object is located - - - Get the primitive details - - - - - - - - - - - - - - - Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the - event - - - Get the simulator the object is located - - - The LocalID of the object - - - Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the - event - - - Get the simulator the object is located - - - The LocalID of the object - - - - Provides updates sit position data - - - - Get the simulator the object is located - - - - - - - - - - - - - - - - - Get the simulator the object is located - - - - - - - - - - - - - Indicates if the operation was successful - - - - - Media version string - - - - - Array of media entries indexed by face number - - - - - Set when simulator sends us infomation on primitive's physical properties - - - - Simulator where the message originated - - - Updated physical properties - - - - Constructor - - Simulator where the message originated - Updated physical properties - - - Size of the byte array used to store raw packet data - - - Raw packet data buffer - - - Length of the data to transmit - - - EndPoint of the remote host - - - - Create an allocated UDP packet buffer for receiving a packet - - - - - Create an allocated UDP packet buffer for sending a packet - - EndPoint of the remote host - - - - Create an allocated UDP packet buffer for sending a packet - - EndPoint of the remote host - Size of the buffer to allocate for packet data - - - - Object pool for packet buffers. This is used to allocate memory for all - incoming and outgoing packets, and zerocoding buffers for those packets - - - - - Creates a new instance of the ObjectPoolBase class. Initialize MUST be called - after using this constructor. - - - - - Creates a new instance of the ObjectPool Base class. - - The object pool is composed of segments, which - are allocated whenever the size of the pool is exceeded. The number of items - in a segment should be large enough that allocating a new segmeng is a rare - thing. For example, on a server that will have 10k people logged in at once, - the receive buffer object pool should have segment sizes of at least 1000 - byte arrays per segment. - - The minimun number of segments that may exist. - Perform a full GC.Collect whenever a segment is allocated, and then again after allocation to compact the heap. - The frequency which segments are checked to see if they're eligible for cleanup. - - - - Forces the segment cleanup algorithm to be run. This method is intended - primarly for use from the Unit Test libraries. - - - - - Responsible for allocate 1 instance of an object that will be stored in a segment. - - An instance of whatever objec the pool is pooling. - - - - Checks in an instance of T owned by the object pool. This method is only intended to be called - by the WrappedObject class. - - The segment from which the instance is checked out. - The instance of T to check back into the segment. - - - - Checks an instance of T from the pool. If the pool is not sufficient to - allow the checkout, a new segment is created. - - A WrappedObject around the instance of T. To check - the instance back into the segment, be sureto dispose the WrappedObject - when finished. - - - - The total number of segments created. Intended to be used by the Unit Tests. - - - - - The number of items that are in a segment. Items in a segment - are all allocated at the same time, and are hopefully close to - each other in the managed heap. - - - - - The minimum number of segments. When segments are reclaimed, - this number of segments will always be left alone. These - segments are allocated at startup. - - - - - The age a segment must be before it's eligible for cleanup. - This is used to prevent thrash, and typical values are in - the 5 minute range. - - - - - The frequence which the cleanup thread runs. This is typically - expected to be in the 5 minute range. - - - - - Initialize the object pool in client mode - - Server to connect to - - - - - - Initialize the object pool in server mode - - - - - - - Returns a packet buffer with EndPoint set if the buffer is in - client mode, or with EndPoint set to null in server mode - - Initialized UDPPacketBuffer object - - - - Default constructor - - - - - Check a packet buffer out of the pool - - A packet buffer object - - - - Checks the instance back into the object pool - - - - - Returns an instance of the class that has been checked out of the Object Pool. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The ObservableDictionary class is used for storing key/value pairs. It has methods for firing - events to subscribers when items are added, removed, or changed. - - Key - Value - - - - A dictionary of callbacks to fire when specified action occurs - - - - - Register a callback to be fired when an action occurs - - The action - The callback to fire - - - - Unregister a callback - - The action - The callback to fire - - - - - - - - - - Internal dictionary that this class wraps around. Do not - modify or enumerate the contents of this dictionary without locking - - - - Initializes a new instance of the Class - with the specified key/value, has the default initial capacity. - - - - // initialize a new ObservableDictionary named testDict with a string as the key and an int as the value. - public ObservableDictionary<string, int> testDict = new ObservableDictionary<string, int>(); - - - - - - Initializes a new instance of the Class - with the specified key/value, With its initial capacity specified. - - Initial size of dictionary - - - // initialize a new ObservableDictionary named testDict with a string as the key and an int as the value, - // initially allocated room for 10 entries. - public ObservableDictionary<string, int> testDict = new ObservableDictionary<string, int>(10); - - - - - - Try to get entry from the with specified key - - Key to use for lookup - Value returned - if specified key exists, if not found - - - // find your avatar using the Simulator.ObjectsAvatars ObservableDictionary: - Avatar av; - if (Client.Network.CurrentSim.ObjectsAvatars.TryGetValue(Client.Self.AgentID, out av)) - Console.WriteLine("Found Avatar {0}", av.Name); - - - - - - - Finds the specified match. - - The match. - Matched value - - - // use a delegate to find a prim in the ObjectsPrimitives ObservableDictionary - // with the ID 95683496 - uint findID = 95683496; - Primitive findPrim = sim.ObjectsPrimitives.Find( - delegate(Primitive prim) { return prim.ID == findID; }); - - - - - Find All items in an - return matching items. - a containing found items. - - Find All prims within 20 meters and store them in a List - - int radius = 20; - List<Primitive> prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll( - delegate(Primitive prim) { - Vector3 pos = prim.Position; - return ((prim.ParentID == 0) && (pos != Vector3.Zero) && (Vector3.Distance(pos, location) < radius)); - } - ); - - - - - Find All items in an - return matching keys. - a containing found keys. - - Find All keys which also exist in another dictionary - - List<UUID> matches = myDict.FindAll( - delegate(UUID id) { - return myOtherDict.ContainsKey(id); - } - ); - - - - - Check if Key exists in Dictionary - Key to check for - if found, otherwise - - - Check if Value exists in Dictionary - Value to check for - if found, otherwise - - - - Adds the specified key to the dictionary, dictionary locking is not performed, - - - The key - The value - - - - Removes the specified key, dictionary locking is not performed - - The key. - if successful, otherwise - - - - Clear the contents of the dictionary - - - - - Enumerator for iterating dictionary entries - - - - - - Gets the number of Key/Value pairs contained in the - - - - - Indexer for the dictionary - - The key - The value + The key of the object + the data to decode + A string represending the fieldData @@ -15555,3408 +6079,6 @@ Recursion level (used for indenting) A formatted string containing the names and values of the source object - - - A custom decoder callback - - The key of the object - the data to decode - A string represending the fieldData - - - - Provides helper methods for parallelizing loops - - - - - Executes a for loop in which iterations may run in parallel - - The loop will be started at this index - The loop will be terminated before this index is reached - Method body to run for each iteration of the loop - - - - Executes a for loop in which iterations may run in parallel - - The number of concurrent execution threads to run - The loop will be started at this index - The loop will be terminated before this index is reached - Method body to run for each iteration of the loop - - - - Executes a foreach loop in which iterations may run in parallel - - Object type that the collection wraps - An enumerable collection to iterate over - Method body to run for each object in the collection - - - - Executes a foreach loop in which iterations may run in parallel - - Object type that the collection wraps - The number of concurrent execution threads to run - An enumerable collection to iterate over - Method body to run for each object in the collection - - - - Executes a series of tasks in parallel - - A series of method bodies to execute - - - - Executes a series of tasks in parallel - - The number of concurrent execution threads to run - A series of method bodies to execute - - - - Type of return to use when returning objects from a parcel - - - - - - - Return objects owned by parcel owner - - - Return objects set to group - - - Return objects not owned by parcel owner or set to group - - - Return a specific list of objects on parcel - - - Return objects that are marked for-sale - - - - Blacklist/Whitelist flags used in parcels Access List - - - - Agent is denied access - - - Agent is granted access - - - - The result of a request for parcel properties - - - - No matches were found for the request - - - Request matched a single parcel - - - Request matched multiple parcels - - - - Flags used in the ParcelAccessListRequest packet to specify whether - we want the access list (whitelist), ban list (blacklist), or both - - - - Request the access list - - - Request the ban list - - - Request both White and Black lists - - - - Sequence ID in ParcelPropertiesReply packets (sent when avatar - tries to cross a parcel border) - - - - Parcel is currently selected - - - Parcel restricted to a group the avatar is not a - member of - - - Avatar is banned from the parcel - - - Parcel is restricted to an access list that the - avatar is not on - - - Response to hovering over a parcel - - - - The tool to use when modifying terrain levels - - - - Level the terrain - - - Raise the terrain - - - Lower the terrain - - - Smooth the terrain - - - Add random noise to the terrain - - - Revert terrain to simulator default - - - - The tool size to use when changing terrain levels - - - - Small - - - Medium - - - Large - - - - Reasons agent is denied access to a parcel on the simulator - - - - Agent is not denied, access is granted - - - Agent is not a member of the group set for the parcel, or which owns the parcel - - - Agent is not on the parcels specific allow list - - - Agent is on the parcels ban list - - - Unknown - - - Agent is not age verified and parcel settings deny access to non age verified avatars - - - - Parcel overlay type. This is used primarily for highlighting and - coloring which is why it is a single integer instead of a set of - flags - - These values seem to be poorly thought out. The first three - bits represent a single value, not flags. For example Auction (0x05) is - not a combination of OwnedByOther (0x01) and ForSale(0x04). However, - the BorderWest and BorderSouth values are bit flags that get attached - to the value stored in the first three bits. Bits four, five, and six - are unused - - - Public land - - - Land is owned by another avatar - - - Land is owned by a group - - - Land is owned by the current avatar - - - Land is for sale - - - Land is being auctioned - - - Land is private - - - To the west of this area is a parcel border - - - To the south of this area is a parcel border - - - - Various parcel properties - - - - No flags set - - - Allow avatars to fly (a client-side only restriction) - - - Allow foreign scripts to run - - - This parcel is for sale - - - Allow avatars to create a landmark on this parcel - - - Allows all avatars to edit the terrain on this parcel - - - Avatars have health and can take damage on this parcel. - If set, avatars can be killed and sent home here - - - Foreign avatars can create objects here - - - All objects on this parcel can be purchased - - - Access is restricted to a group - - - Access is restricted to a whitelist - - - Ban blacklist is enabled - - - Unknown - - - List this parcel in the search directory - - - Allow personally owned parcels to be deeded to group - - - If Deeded, owner contributes required tier to group parcel is deeded to - - - Restrict sounds originating on this parcel to the - parcel boundaries - - - Objects on this parcel are sold when the land is - purchsaed - - - Allow this parcel to be published on the web - - - The information for this parcel is mature content - - - The media URL is an HTML page - - - The media URL is a raw HTML string - - - Restrict foreign object pushes - - - Ban all non identified/transacted avatars - - - Allow group-owned scripts to run - - - Allow object creation by group members or group - objects - - - Allow all objects to enter this parcel - - - Only allow group and owner objects to enter this parcel - - - Voice Enabled on this parcel - - - Use Estate Voice channel for Voice on this parcel - - - Deny Age Unverified Users - - - - Parcel ownership status - - - - Placeholder - - - Parcel is leased (owned) by an avatar or group - - - Parcel is in process of being leased (purchased) by an avatar or group - - - Parcel has been abandoned back to Governor Linden - - - - Category parcel is listed in under search - - - - No assigned category - - - Linden Infohub or public area - - - Adult themed area - - - Arts and Culture - - - Business - - - Educational - - - Gaming - - - Hangout or Club - - - Newcomer friendly - - - Parks and Nature - - - Residential - - - Shopping - - - Not Used? - - - Other - - - Not an actual category, only used for queries - - - - Type of teleport landing for a parcel - - - - Unset, simulator default - - - Specific landing point set for this parcel - - - No landing point set, direct teleports enabled for - this parcel - - - - Parcel Media Command used in ParcelMediaCommandMessage - - - - Stop the media stream and go back to the first frame - - - Pause the media stream (stop playing but stay on current frame) - - - Start the current media stream playing and stop when the end is reached - - - Start the current media stream playing, - loop to the beginning when the end is reached and continue to play - - - Specifies the texture to replace with video - If passing the key of a texture, it must be explicitly typecast as a key, - not just passed within double quotes. - - - Specifies the movie URL (254 characters max) - - - Specifies the time index at which to begin playing - - - Specifies a single agent to apply the media command to - - - Unloads the stream. While the stop command sets the texture to the first frame of the movie, - unload resets it to the real texture that the movie was replacing. - - - Turn on/off the auto align feature, similar to the auto align checkbox in the parcel media properties - (NOT to be confused with the "align" function in the textures view of the editor!) Takes TRUE or FALSE as parameter. - - - Allows a Web page or image to be placed on a prim (1.19.1 RC0 and later only). - Use "text/html" for HTML. - - - Resizes a Web page to fit on x, y pixels (1.19.1 RC0 and later only). - This might still not be working - - - Sets a description for the media being displayed (1.19.1 RC0 and later only). - - - - Some information about a parcel of land returned from a DirectoryManager search - - - - Global Key of record - - - Parcel Owners - - - Name field of parcel, limited to 128 characters - - - Description field of parcel, limited to 256 characters - - - Total Square meters of parcel - - - Total area billable as Tier, for group owned land this will be 10% less than ActualArea - - - True of parcel is in Mature simulator - - - Grid global X position of parcel - - - Grid global Y position of parcel - - - Grid global Z position of parcel (not used) - - - Name of simulator parcel is located in - - - Texture of parcels display picture - - - Float representing calculated traffic based on time spent on parcel by avatars - - - Sale price of parcel (not used) - - - Auction ID of parcel - - - - Parcel Media Information - - - - A byte, if 0x1 viewer should auto scale media to fit object - - - A boolean, if true the viewer should loop the media - - - The Asset UUID of the Texture which when applied to a - primitive will display the media - - - A URL which points to any Quicktime supported media type - - - A description of the media - - - An Integer which represents the height of the media - - - An integer which represents the width of the media - - - A string which contains the mime type of the media - - - - Parcel of land, a portion of virtual real estate in a simulator - - - - The total number of contiguous 4x4 meter blocks your agent owns within this parcel - - - The total number of contiguous 4x4 meter blocks contained in this parcel owned by a group or agent other than your own - - - Deprecated, Value appears to always be 0 - - - Simulator-local ID of this parcel - - - UUID of the owner of this parcel - - - Whether the land is deeded to a group or not - - - - - - Date land was claimed - - - Appears to always be zero - - - This field is no longer used - - - Minimum corner of the axis-aligned bounding box for this - parcel - - - Maximum corner of the axis-aligned bounding box for this - parcel - - - Bitmap describing land layout in 4x4m squares across the - entire region - - - Total parcel land area - - - - - - Maximum primitives across the entire simulator owned by the same agent or group that owns this parcel that can be used - - - Total primitives across the entire simulator calculated by combining the allowed prim counts for each parcel - owned by the agent or group that owns this parcel - - - Maximum number of primitives this parcel supports - - - Total number of primitives on this parcel - - - For group-owned parcels this indicates the total number of prims deeded to the group, - for parcels owned by an individual this inicates the number of prims owned by the individual - - - Total number of primitives owned by the parcel group on - this parcel, or for parcels owned by an individual with a group set the - total number of prims set to that group. - - - Total number of prims owned by other avatars that are not set to group, or not the parcel owner - - - A bonus multiplier which allows parcel prim counts to go over times this amount, this does not affect - the max prims per simulator. e.g: 117 prim parcel limit x 1.5 bonus = 175 allowed - - - Autoreturn value in minutes for others' objects - - - - - - Sale price of the parcel, only useful if ForSale is set - The SalePrice will remain the same after an ownership - transfer (sale), so it can be used to see the purchase price after - a sale if the new owner has not changed it - - - Parcel Name - - - Parcel Description - - - URL For Music Stream - - - - - - Price for a temporary pass - - - How long is pass valid for - - - - - - Key of authorized buyer - - - Key of parcel snapshot - - - The landing point location - - - The landing point LookAt - - - The type of landing enforced from the enum - - - - - - - - - - - - Access list of who is whitelisted on this - parcel - - - Access list of who is blacklisted on this - parcel - - - TRUE of region denies access to age unverified users - - - true to obscure (hide) media url - - - true to obscure (hide) music url - - - A struct containing media details - - - - Displays a parcel object in string format - - string containing key=value pairs of a parcel object - - - - Defalt constructor - - Local ID of this parcel - - - - Update the simulator with any local changes to this Parcel object - - Simulator to send updates to - Whether we want the simulator to confirm - the update with a reply packet or not - - - - Set Autoreturn time - - Simulator to send the update to - - - - Parcel (subdivided simulator lots) subsystem - - - - The event subscribers. null if no subcribers - - - Raises the ParcelDwellReply event - A ParcelDwellReplyEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the ParcelInfoReply event - A ParcelInfoReplyEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the ParcelProperties event - A ParcelPropertiesEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the ParcelAccessListReply event - A ParcelAccessListReplyEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the ParcelObjectOwnersReply event - A ParcelObjectOwnersReplyEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the SimParcelsDownloaded event - A SimParcelsDownloadedEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the ForceSelectObjectsReply event - A ForceSelectObjectsReplyEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the ParcelMediaUpdateReply event - A ParcelMediaUpdateReplyEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the ParcelMediaCommand event - A ParcelMediaCommandEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - - Default constructor - - A reference to the GridClient object - - - - Request basic information for a single parcel - - Simulator-local ID of the parcel - - - - Request properties of a single parcel - - Simulator containing the parcel - Simulator-local ID of the parcel - An arbitrary integer that will be returned - with the ParcelProperties reply, useful for distinguishing between - multiple simultaneous requests - - - - Request the access list for a single parcel - - Simulator containing the parcel - Simulator-local ID of the parcel - An arbitrary integer that will be returned - with the ParcelAccessList reply, useful for distinguishing between - multiple simultaneous requests - - - - - Request properties of parcels using a bounding box selection - - Simulator containing the parcel - Northern boundary of the parcel selection - Eastern boundary of the parcel selection - Southern boundary of the parcel selection - Western boundary of the parcel selection - An arbitrary integer that will be returned - with the ParcelProperties reply, useful for distinguishing between - different types of parcel property requests - A boolean that is returned with the - ParcelProperties reply, useful for snapping focus to a single - parcel - - - - Request all simulator parcel properties (used for populating the Simulator.Parcels - dictionary) - - Simulator to request parcels from (must be connected) - - - - Request all simulator parcel properties (used for populating the Simulator.Parcels - dictionary) - - Simulator to request parcels from (must be connected) - If TRUE, will force a full refresh - Number of milliseconds to pause in between each request - - - - Request the dwell value for a parcel - - Simulator containing the parcel - Simulator-local ID of the parcel - - - - Send a request to Purchase a parcel of land - - The Simulator the parcel is located in - The parcels region specific local ID - true if this parcel is being purchased by a group - The groups - true to remove tier contribution if purchase is successful - The parcels size - The purchase price of the parcel - - - - - Reclaim a parcel of land - - The simulator the parcel is in - The parcels region specific local ID - - - - Deed a parcel to a group - - The simulator the parcel is in - The parcels region specific local ID - The groups - - - - Request prim owners of a parcel of land. - - Simulator parcel is in - The parcels region specific local ID - - - - Return objects from a parcel - - Simulator parcel is in - The parcels region specific local ID - the type of objects to return, - A list containing object owners s to return - - - - Subdivide (split) a parcel - - - - - - - - - - Join two parcels of land creating a single parcel - - - - - - - - - - Get a parcels LocalID - - Simulator parcel is in - Vector3 position in simulator (Z not used) - 0 on failure, or parcel LocalID on success. - A call to Parcels.RequestAllSimParcels is required to populate map and - dictionary. - - - - Terraform (raise, lower, etc) an area or whole parcel of land - - Simulator land area is in. - LocalID of parcel, or -1 if using bounding box - From Enum, Raise, Lower, Level, Smooth, Etc. - Size of area to modify - true on successful request sent. - Settings.STORE_LAND_PATCHES must be true, - Parcel information must be downloaded using RequestAllSimParcels() - - - - Terraform (raise, lower, etc) an area or whole parcel of land - - Simulator land area is in. - west border of area to modify - south border of area to modify - east border of area to modify - north border of area to modify - From Enum, Raise, Lower, Level, Smooth, Etc. - Size of area to modify - true on successful request sent. - Settings.STORE_LAND_PATCHES must be true, - Parcel information must be downloaded using RequestAllSimParcels() - - - - Terraform (raise, lower, etc) an area or whole parcel of land - - Simulator land area is in. - LocalID of parcel, or -1 if using bounding box - west border of area to modify - south border of area to modify - east border of area to modify - north border of area to modify - From Enum, Raise, Lower, Level, Smooth, Etc. - Size of area to modify - How many meters + or - to lower, 1 = 1 meter - true on successful request sent. - Settings.STORE_LAND_PATCHES must be true, - Parcel information must be downloaded using RequestAllSimParcels() - - - - Terraform (raise, lower, etc) an area or whole parcel of land - - Simulator land area is in. - LocalID of parcel, or -1 if using bounding box - west border of area to modify - south border of area to modify - east border of area to modify - north border of area to modify - From Enum, Raise, Lower, Level, Smooth, Etc. - Size of area to modify - How many meters + or - to lower, 1 = 1 meter - Height at which the terraform operation is acting at - - - - Sends a request to the simulator to return a list of objects owned by specific owners - - Simulator local ID of parcel - Owners, Others, Etc - List containing keys of avatars objects to select; - if List is null will return Objects of type selectType - Response data is returned in the event - - - - Eject and optionally ban a user from a parcel - - target key of avatar to eject - true to also ban target - - - - Freeze or unfreeze an avatar over your land - - target key to freeze - true to freeze, false to unfreeze - - - - Abandon a parcel of land - - Simulator parcel is in - Simulator local ID of parcel - - - - Requests the UUID of the parcel in a remote region at a specified location - - Location of the parcel in the remote region - Remote region handle - Remote region UUID - If successful UUID of the remote parcel, UUID.Zero otherwise - - - - Retrieves information on resources used by the parcel - - UUID of the parcel - Should per object resource usage be requested - Callback invoked when the request is complete - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - Raises the event - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - Raises the event - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - Raises the event - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - Raises the event - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - Raises the event - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - Raises the event - - - Raised when the simulator responds to a request - - - Raised when the simulator responds to a request - - - Raised when the simulator responds to a request - - - Raised when the simulator responds to a request - - - Raised when the simulator responds to a request - - - Raised when the simulator responds to a request - - - Raised when the simulator responds to a request - - - Raised when the simulator responds to a Parcel Update request - - - Raised when the parcel your agent is located sends a ParcelMediaCommand - - - - Parcel Accesslist - - - - Agents - - - - - - Flags for specific entry in white/black lists - - - - Owners of primitives on parcel - - - - Prim Owners - - - True of owner is group - - - Total count of prims owned by OwnerID - - - true of OwnerID is currently online and is not a group - - - The date of the most recent prim left by OwnerID - - - - Called once parcel resource usage information has been collected - - Indicates if operation was successfull - Parcel resource usage information - - - Contains a parcels dwell data returned from the simulator in response to an - - - - Construct a new instance of the ParcelDwellReplyEventArgs class - - The global ID of the parcel - The simulator specific ID of the parcel - The calculated dwell for the parcel - - - Get the global ID of the parcel - - - Get the simulator specific ID of the parcel - - - Get the calculated dwell - - - Contains basic parcel information data returned from the - simulator in response to an request - - - - Construct a new instance of the ParcelInfoReplyEventArgs class - - The object containing basic parcel info - - - Get the object containing basic parcel info - - - Contains basic parcel information data returned from the simulator in response to an request - - - - Construct a new instance of the ParcelPropertiesEventArgs class - - The object containing the details - The object containing the details - The result of the request - The number of primitieves your agent is - currently selecting and or sitting on in this parcel - The user assigned ID used to correlate a request with - these results - TODO: - - - Get the simulator the parcel is located in - - - Get the object containing the details - If Result is NoData, this object will not contain valid data - - - Get the result of the request - - - Get the number of primitieves your agent is - currently selecting and or sitting on in this parcel - - - Get the user assigned ID used to correlate a request with - these results - - - TODO: - - - Contains blacklist and whitelist data returned from the simulator in response to an request - - - - Construct a new instance of the ParcelAccessListReplyEventArgs class - - The simulator the parcel is located in - The user assigned ID used to correlate a request with - these results - The simulator specific ID of the parcel - TODO: - The list containing the white/blacklisted agents for the parcel - - - Get the simulator the parcel is located in - - - Get the user assigned ID used to correlate a request with - these results - - - Get the simulator specific ID of the parcel - - - TODO: - - - Get the list containing the white/blacklisted agents for the parcel - - - Contains blacklist and whitelist data returned from the - simulator in response to an request - - - - Construct a new instance of the ParcelObjectOwnersReplyEventArgs class - - The simulator the parcel is located in - The list containing prim ownership counts - - - Get the simulator the parcel is located in - - - Get the list containing prim ownership counts - - - Contains the data returned when all parcel data has been retrieved from a simulator - - - - Construct a new instance of the SimParcelsDownloadedEventArgs class - - The simulator the parcel data was retrieved from - The dictionary containing the parcel data - The multidimensional array containing a x,y grid mapped - to each 64x64 parcel's LocalID. - - - Get the simulator the parcel data was retrieved from - - - A dictionary containing the parcel data where the key correlates to the ParcelMap entry - - - Get the multidimensional array containing a x,y grid mapped - to each 64x64 parcel's LocalID. - - - Contains the data returned when a request - - - - Construct a new instance of the ForceSelectObjectsReplyEventArgs class - - The simulator the parcel data was retrieved from - The list of primitive IDs - true if the list is clean and contains the information - only for a given request - - - Get the simulator the parcel data was retrieved from - - - Get the list of primitive IDs - - - true if the list is clean and contains the information - only for a given request - - - Contains data when the media data for a parcel the avatar is on changes - - - - Construct a new instance of the ParcelMediaUpdateReplyEventArgs class - - the simulator the parcel media data was updated in - The updated media information - - - Get the simulator the parcel media data was updated in - - - Get the updated media information - - - Contains the media command for a parcel the agent is currently on - - - - Construct a new instance of the ParcelMediaCommandEventArgs class - - The simulator the parcel media command was issued in - - - The media command that was sent - - - - Get the simulator the parcel media command was issued in - - - - - - - - - Get the media command that was sent - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Class for controlling various system settings. - - Some values are readonly because they affect things that - happen when the GridClient object is initialized, so changing them at - runtime won't do any good. Non-readonly values may affect things that - happen at login or dynamically - - - Main grid login server - - - Beta grid login server - - - - InventoryManager requests inventory information on login, - GridClient initializes an Inventory store for main inventory. - - - - - InventoryManager requests library information on login, - GridClient initializes an Inventory store for the library. - - - - Number of milliseconds between sending pings to each sim - - - Number of milliseconds between sending camera updates - - - Number of milliseconds between updating the current - positions of moving, non-accelerating and non-colliding objects - - - Millisecond interval between ticks, where all ACKs are - sent out and the age of unACKed packets is checked - - - The initial size of the packet inbox, where packets are - stored before processing - - - Maximum size of packet that we want to send over the wire - - - The maximum value of a packet sequence number before it - rolls over back to one - - - The relative directory where external resources are kept - - - Login server to connect to - - - IP Address the client will bind to - - - Use XML-RPC Login or LLSD Login, default is XML-RPC Login - - - - Maximum number of HTTP connections to open to a particular endpoint. - - - An endpoint is defined as a commbination of network address and port. This is used for Caps. - This is a static variable which applies to all instances. - - - - - Use Caps for fetching inventory where available - - - - Number of milliseconds before an asset transfer will time - out - - - Number of milliseconds before a teleport attempt will time - out - - - Number of milliseconds before NetworkManager.Logout() will - time out - - - Number of milliseconds before a CAPS call will time out - Setting this too low will cause web requests time out and - possibly retry repeatedly - - - Number of milliseconds for xml-rpc to timeout - - - Milliseconds before a packet is assumed lost and resent - - - Milliseconds without receiving a packet before the - connection to a simulator is assumed lost - - - Milliseconds to wait for a simulator info request through - the grid interface - - - The maximum size of the sequence number archive, used to - check for resent and/or duplicate packets - - - Maximum number of queued ACKs to be sent before SendAcks() - is forced - - - Network stats queue length (seconds) - - - - Primitives will be reused when falling in/out of interest list (and shared between clients) - prims returning to interest list do not need re-requested - Helps also in not re-requesting prim.Properties for code that checks for a Properties == null per client - - - - - Pool parcel data between clients (saves on requesting multiple times when all clients may need it) - - - - - How long to preserve cached data when no client is connected to a simulator - The reason for setting it to something like 2 minutes is in case a client - is running back and forth between region edges or a sim is comming and going - - - - Enable/disable storing terrain heightmaps in the - TerrainManager - - - Enable/disable sending periodic camera updates - - - Enable/disable automatically setting agent appearance at - login and after sim crossing - - - Enable/disable automatically setting the bandwidth throttle - after connecting to each simulator - The default throttle uses the equivalent of the maximum - bandwidth setting in the official client. If you do not set a - throttle your connection will by default be throttled well below - the minimum values and you may experience connection problems - - - Enable/disable the sending of pings to monitor lag and - packet loss - - - Should we connect to multiple sims? This will allow - viewing in to neighboring simulators and sim crossings - (Experimental) - - - If true, all object update packets will be decoded in to - native objects. If false, only updates for our own agent will be - decoded. Registering an event handler will force objects for that - type to always be decoded. If this is disabled the object tracking - will have missing or partial prim and avatar information - - - If true, when a cached object check is received from the - server the full object info will automatically be requested - - - Whether to establish connections to HTTP capabilities - servers for simulators - - - Whether to decode sim stats - - - The capabilities servers are currently designed to - periodically return a 502 error which signals for the client to - re-establish a connection. Set this to true to log those 502 errors - - - If true, any reference received for a folder or item - the library is not aware of will automatically be fetched - - - If true, and SEND_AGENT_UPDATES is true, - AgentUpdate packets will continuously be sent out to give the bot - smoother movement and autopiloting - - - If true, currently visible avatars will be stored - in dictionaries inside Simulator.ObjectAvatars. - If false, a new Avatar or Primitive object will be created - each time an object update packet is received - - - If true, currently visible avatars will be stored - in dictionaries inside Simulator.ObjectPrimitives. - If false, a new Avatar or Primitive object will be created - each time an object update packet is received - - - If true, position and velocity will periodically be - interpolated (extrapolated, technically) for objects and - avatars that are being tracked by the library. This is - necessary to increase the accuracy of speed and position - estimates for simulated objects - - - - If true, utilization statistics will be tracked. There is a minor penalty - in CPU time for enabling this option. - - - - If true, parcel details will be stored in the - Simulator.Parcels dictionary as they are received - - - - If true, an incoming parcel properties reply will automatically send - a request for the parcel access list - - - - - if true, an incoming parcel properties reply will automatically send - a request for the traffic count. - - - - - If true, images, and other assets downloaded from the server - will be cached in a local directory - - - - Path to store cached texture data - - - Maximum size cached files are allowed to take on disk (bytes) - - - Default color used for viewer particle effects - - - Maximum number of times to resend a failed packet - - - Throttle outgoing packet rate - - - UUID of a texture used by some viewers to indentify type of client used - - - - Download textures using GetTexture capability when available - - - - The maximum number of concurrent texture downloads allowed - Increasing this number will not necessarily increase texture retrieval times due to - simulator throttles - - - - The Refresh timer inteval is used to set the delay between checks for stalled texture downloads - - This is a static variable which applies to all instances - - - - Textures taking longer than this value will be flagged as timed out and removed from the pipeline - - - - - Get or set the minimum log level to output to the console by default - - If the library is not compiled with DEBUG defined and this level is set to DEBUG - You will get no output on the console. This behavior can be overriden by creating - a logger configuration file for log4net - - - - Attach avatar names to log messages - - - Log packet retransmission info - - - Log disk cache misses and other info - - - Constructor - Reference to a GridClient object - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Cost of uploading an asset - Read-only since this value is dynamically fetched at login - - - - Simulator (region) properties - - - - No flags set - - - Agents can take damage and be killed - - - Landmarks can be created here - - - Home position can be set in this sim - - - Home position is reset when an agent teleports away - - - Sun does not move - - - No object, land, etc. taxes - - - Disable heightmap alterations (agents can still plant - foliage) - - - Land cannot be released, sold, or purchased - - - All content is wiped nightly - - - Unknown: Related to the availability of an overview world map tile.(Think mainland images when zoomed out.) - - - Unknown: Related to region debug flags. Possibly to skip processing of agent interaction with world. - - - Region does not update agent prim interest lists. Internal debugging option. - - - No collision detection for non-agent objects - - - No scripts are ran - - - All physics processing is turned off - - - Region can be seen from other regions on world map. (Legacy world map option?) - - - Region can be seen from mainland on world map. (Legacy world map option?) - - - Agents not explicitly on the access list can visit the region. - - - Traffic calculations are not run across entire region, overrides parcel settings. - - - Flight is disabled (not currently enforced by the sim) - - - Allow direct (p2p) teleporting - - - Estate owner has temporarily disabled scripting - - - Restricts the usage of the LSL llPushObject function, applies to whole region. - - - Deny agents with no payment info on file - - - Deny agents with payment info on file - - - Deny agents who have made a monetary transaction - - - Parcels within the region may be joined or divided by anyone, not just estate owners/managers. - - - Abuse reports sent from within this region are sent to the estate owner defined email. - - - Region is Voice Enabled - - - Removes the ability from parcel owners to set their parcels to show in search. - - - Deny agents who have not been age verified from entering the region. - - - - Region protocol flags - - - - Nothing special - - - Region supports Server side Appearance - - - Viewer supports Server side Appearance - - - - Access level for a simulator - - - - Unknown or invalid access level - - - Trial accounts allowed - - - PG rating - - - Mature rating - - - Adult rating - - - Simulator is offline - - - Simulator does not exist - - - - - - - - - - - - - - Initialize the UDP packet handler in server mode - - Port to listening for incoming UDP packets on - - - - Initialize the UDP packet handler in client mode - - Remote UDP server to connect to - - - - - - - - - - - - - - - - - - A public reference to the client that this Simulator object - is attached to - - - A Unique Cache identifier for this simulator - - - The capabilities for this simulator - - - - - - The current version of software this simulator is running - - - - - - A 64x64 grid of parcel coloring values. The values stored - in this array are of the type - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true if your agent has Estate Manager rights on this region - - - - - - - - - - - - Statistics information for this simulator and the - connection to the simulator, calculated by the simulator itself - and the library - - - The regions Unique ID - - - The physical data center the simulator is located - Known values are: - - Dallas - Chandler - SF - - - - - The CPU Class of the simulator - Most full mainland/estate sims appear to be 5, - Homesteads and Openspace appear to be 501 - - - The number of regions sharing the same CPU as this one - "Full Sims" appear to be 1, Homesteads appear to be 4 - - - The billing product name - Known values are: - - Mainland / Full Region (Sku: 023) - Estate / Full Region (Sku: 024) - Estate / Openspace (Sku: 027) - Estate / Homestead (Sku: 029) - Mainland / Homestead (Sku: 129) (Linden Owned) - Mainland / Linden Homes (Sku: 131) - - - - - The billing product SKU - Known values are: - - 023 Mainland / Full Region - 024 Estate / Full Region - 027 Estate / Openspace - 029 Estate / Homestead - 129 Mainland / Homestead (Linden Owned) - 131 Linden Homes / Full Region - - - - - - Flags indicating which protocols this region supports - - - - The current sequence number for packets sent to this - simulator. Must be Interlocked before modifying. Only - useful for applications manipulating sequence numbers - - - - A thread-safe dictionary containing avatars in a simulator - - - - - A thread-safe dictionary containing primitives in a simulator - - - - - Checks simulator parcel map to make sure it has downloaded all data successfully - - true if map is full (contains no 0's) - - - - Is it safe to send agent updates to this sim - AgentMovementComplete message received - - - - Used internally to track sim disconnections - - - Event that is triggered when the simulator successfully - establishes a connection - - - Whether this sim is currently connected or not. Hooked up - to the property Connected - - - Coarse locations of avatars in this simulator - - - AvatarPositions key representing TrackAgent target - - - Sequence numbers of packets we've received - (for duplicate checking) - - - Packets we sent out that need ACKs from the simulator - - - Sequence number for pause/resume - - - Indicates if UDP connection to the sim is fully established - - - - - - Reference to the GridClient object - IPEndPoint of the simulator - handle of the simulator - - - - Called when this Simulator object is being destroyed - - - - - Attempt to connect to this simulator - - Whether to move our agent in to this sim or not - True if the connection succeeded or connection status is - unknown, false if there was a failure - - - - Initiates connection to the simulator - - Should we block until ack for this packet is recieved - - - - Disconnect from this simulator - - - - - Instructs the simulator to stop sending update (and possibly other) packets - - - - - Instructs the simulator to resume sending update packets (unpause) - - - - - Retrieve the terrain height at a given coordinate - - Sim X coordinate, valid range is from 0 to 255 - Sim Y coordinate, valid range is from 0 to 255 - The terrain height at the given point if the - lookup was successful, otherwise 0.0f - True if the lookup was successful, otherwise false - - - - Sends a packet - - Packet to be sent - - - - - - - - - Returns Simulator Name as a String - - - - - - - - - - - - - - - - - - - Sends out pending acknowledgements - - Number of ACKs sent - - - - Resend unacknowledged packets - - - - - Provides access to an internal thread-safe dictionary containing parcel - information found in this simulator - - - - - Provides access to an internal thread-safe multidimensional array containing a x,y grid mapped - to each 64x64 parcel's LocalID. - - - - The IP address and port of the server - - - Whether there is a working connection to the simulator or - not - - - Coarse locations of avatars in this simulator - - - AvatarPositions key representing TrackAgent target - - - Indicates if UDP connection to the sim is fully established - - - - Simulator Statistics - - - - Total number of packets sent by this simulator to this agent - - - Total number of packets received by this simulator to this agent - - - Total number of bytes sent by this simulator to this agent - - - Total number of bytes received by this simulator to this agent - - - Time in seconds agent has been connected to simulator - - - Total number of packets that have been resent - - - Total number of resent packets recieved - - - Total number of pings sent to this simulator by this agent - - - Total number of ping replies sent to this agent by this simulator - - - - Incoming bytes per second - - It would be nice to have this claculated on the fly, but - this is far, far easier - - - - Outgoing bytes per second - - It would be nice to have this claculated on the fly, but - this is far, far easier - - - Time last ping was sent - - - ID of last Ping sent - - - - - - - - - Current time dilation of this simulator - - - Current Frames per second of simulator - - - Current Physics frames per second of simulator - - - - - - - - - - - - - - - - - - - - - - - - - - - Total number of objects Simulator is simulating - - - Total number of Active (Scripted) objects running - - - Number of agents currently in this simulator - - - Number of agents in neighbor simulators - - - Number of Active scripts running in this simulator - - - - - - - - - - - - Number of downloads pending - - - Number of uploads pending - - - - - - - - - Number of local uploads pending - - - Unacknowledged bytes in queue - - - - Simulator handle - - - - - Number of GridClients using this datapool - - - - - Time that the last client disconnected from the simulator - - - - - The cache of prims used and unused in this simulator - - - - - Shared parcel info only when POOL_PARCEL_DATA == true - - - - - - - - - The event subscribers, null of no subscribers - - - Raises the AttachedSound Event - A AttachedSoundEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the AttachedSoundGainChange Event - A AttachedSoundGainChangeEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the SoundTrigger Event - A SoundTriggerEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the PreloadSound Event - A PreloadSoundEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - - Construct a new instance of the SoundManager class, used for playing and receiving - sound assets - - A reference to the current GridClient instance - - - - Plays a sound in the current region at full volume from avatar position - - UUID of the sound to be played - - - - Plays a sound in the current region at full volume - - UUID of the sound to be played. - position for the sound to be played at. Normally the avatar. - - - - Plays a sound in the current region - - UUID of the sound to be played. - position for the sound to be played at. Normally the avatar. - volume of the sound, from 0.0 to 1.0 - - - - Plays a sound in the specified sim - - UUID of the sound to be played. - UUID of the sound to be played. - position for the sound to be played at. Normally the avatar. - volume of the sound, from 0.0 to 1.0 - - - - Play a sound asset - - UUID of the sound to be played. - handle id for the sim to be played in. - position for the sound to be played at. Normally the avatar. - volume of the sound, from 0.0 to 1.0 - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - - - Raised when the simulator sends us data containing - sound - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Raised when the simulator sends us data containing - ... - - - Provides data for the event - The event occurs when the simulator sends - the sound data which emits from an agents attachment - - The following code example shows the process to subscribe to the event - and a stub to handle the data passed from the simulator - - // Subscribe to the AttachedSound event - Client.Sound.AttachedSound += Sound_AttachedSound; - - // process the data raised in the event here - private void Sound_AttachedSound(object sender, AttachedSoundEventArgs e) - { - // ... Process AttachedSoundEventArgs here ... - } - - - - - - Construct a new instance of the SoundTriggerEventArgs class - - Simulator where the event originated - The sound asset id - The ID of the owner - The ID of the object - The volume level - The - - - Simulator where the event originated - - - Get the sound asset id - - - Get the ID of the owner - - - Get the ID of the Object - - - Get the volume level - - - Get the - - - Provides data for the event - The event occurs when an attached sound - changes its volume level - - - - Construct a new instance of the AttachedSoundGainChangedEventArgs class - - Simulator where the event originated - The ID of the Object - The new volume level - - - Simulator where the event originated - - - Get the ID of the Object - - - Get the volume level - - - Provides data for the event - The event occurs when the simulator forwards - a request made by yourself or another agent to play either an asset sound or a built in sound - - Requests to play sounds where the is not one of the built-in - will require sending a request to download the sound asset before it can be played - - - The following code example uses the , - and - properties to display some information on a sound request on the window. - - // subscribe to the event - Client.Sound.SoundTrigger += Sound_SoundTrigger; - - // play the pre-defined BELL_TING sound - Client.Sound.SendSoundTrigger(Sounds.BELL_TING); - - // handle the response data - private void Sound_SoundTrigger(object sender, SoundTriggerEventArgs e) - { - Console.WriteLine("{0} played the sound {1} at volume {2}", - e.OwnerID, e.SoundID, e.Gain); - } - - - - - - Construct a new instance of the SoundTriggerEventArgs class - - Simulator where the event originated - The sound asset id - The ID of the owner - The ID of the object - The ID of the objects parent - The volume level - The regionhandle - The source position - - - Simulator where the event originated - - - Get the sound asset id - - - Get the ID of the owner - - - Get the ID of the Object - - - Get the ID of the objects parent - - - Get the volume level - - - Get the regionhandle - - - Get the source position - - - Provides data for the event - The event occurs when the simulator sends - the appearance data for an avatar - - The following code example uses the and - properties to display the selected shape of an avatar on the window. - - // subscribe to the event - Client.Avatars.AvatarAppearance += Avatars_AvatarAppearance; - - // handle the data when the event is raised - void Avatars_AvatarAppearance(object sender, AvatarAppearanceEventArgs e) - { - Console.WriteLine("The Agent {0} is using a {1} shape.", e.AvatarID, (e.VisualParams[31] > 0) : "male" ? "female") - } - - - - - - Construct a new instance of the PreloadSoundEventArgs class - - Simulator where the event originated - The sound asset id - The ID of the owner - The ID of the object - - - Simulator where the event originated - - - Get the sound asset id - - - Get the ID of the owner - - - Get the ID of the Object - - - - pre-defined built in sounds - - - - - - - - - - - - - - - - - - - - - - - - - - - - coins - - - cash register bell - - - - - - - - - rubber - - - plastic - - - flesh - - - wood splintering? - - - glass break - - - metal clunk - - - whoosh - - - shake - - - - - - ding - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A dictionary containing all pre-defined sounds - - A dictionary containing the pre-defined sounds, - where the key is the sounds ID, and the value is a string - containing a name to identify the purpose of the sound - - - X position of this patch - - - Y position of this patch - - - A 16x16 array of floats holding decompressed layer data - - - - Creates a LayerData packet for compressed land data given a full - simulator heightmap and an array of indices of patches to compress - - A 256 * 256 array of floating point values - specifying the height at each meter in the simulator - Array of indexes in the 16x16 grid of patches - for this simulator. For example if 1 and 17 are specified, patches - x=1,y=0 and x=1,y=1 are sent - - - - - Add a patch of terrain to a BitPacker - - BitPacker to write the patch to - Heightmap of the simulator, must be a 256 * - 256 float array - X offset of the patch to create, valid values are - from 0 to 15 - Y offset of the patch to create, valid values are - from 0 to 15 - - - The event subscribers. null if no subcribers - - - Raises the LandPatchReceived event - A LandPatchReceivedEventArgs object containing the - data returned from the simulator - - - Thread sync lock object - - - - Default constructor - - - - - Raised when the simulator responds sends - - - Simulator from that sent tha data - - - Sim coordinate of the patch - - - Sim coordinate of the patch - - - Size of tha patch - - - Heightmap for the patch - - - - The current status of a texture request as it moves through the pipeline or final result of a texture request. - - - - The initial state given to a request. Requests in this state - are waiting for an available slot in the pipeline - - - A request that has been added to the pipeline and the request packet - has been sent to the simulator - - - A request that has received one or more packets back from the simulator - - - A request that has received all packets back from the simulator - - - A request that has taken longer than - to download OR the initial packet containing the packet information was never received - - - The texture request was aborted by request of the agent - - - The simulator replied to the request that it was not able to find the requested texture - - - - A callback fired to indicate the status or final state of the requested texture. For progressive - downloads this will fire each time new asset data is returned from the simulator. - - The indicating either Progress for textures not fully downloaded, - or the final result of the request after it has been processed through the TexturePipeline - The object containing the Assets ID, raw data - and other information. For progressive rendering the will contain - the data from the beginning of the file. For failed, aborted and timed out requests it will contain - an empty byte array. - - - - Texture request download handler, allows a configurable number of download slots which manage multiple - concurrent texture downloads from the - - This class makes full use of the internal - system for full texture downloads. - - - A dictionary containing all pending and in-process transfer requests where the Key is both the RequestID - and also the Asset Texture ID, and the value is an object containing the current state of the request and also - the asset data as it is being re-assembled - - - Holds the reference to the client object - - - Maximum concurrent texture requests allowed at a time - - - An array of objects used to manage worker request threads - - - An array of worker slots which shows the availablity status of the slot - - - The primary thread which manages the requests. - - - true if the TexturePipeline is currently running - - - A synchronization object used by the primary thread - - - A refresh timer used to increase the priority of stalled requests - - - - Default constructor, Instantiates a new copy of the TexturePipeline class - - Reference to the instantiated object - - - - Initialize callbacks required for the TexturePipeline to operate - - - - - Shutdown the TexturePipeline and cleanup any callbacks or transfers - - - - - Request a texture asset from the simulator using the system to - manage the requests and re-assemble the image from the packets received from the simulator - - The of the texture asset to download - The of the texture asset. - Use for most textures, or for baked layer texture assets - A float indicating the requested priority for the transfer. Higher priority values tell the simulator - to prioritize the request before lower valued requests. An image already being transferred using the can have - its priority changed by resending the request with the new priority value - Number of quality layers to discard. - This controls the end marker of the data sent - The packet number to begin the request at. A value of 0 begins the request - from the start of the asset texture - The callback to fire when the image is retrieved. The callback - will contain the result of the request and the texture asset data - If true, the callback will be fired for each chunk of the downloaded image. - The callback asset parameter will contain all previously received chunks of the texture asset starting - from the beginning of the request - - - - Sends the actual request packet to the simulator - - The image to download - Type of the image to download, either a baked - avatar texture or a normal texture - Priority level of the download. Default is - 1,013,000.0f - Number of quality layers to discard. - This controls the end marker of the data sent - Packet number to start the download at. - This controls the start marker of the data sent - Sending a priority of 0 and a discardlevel of -1 aborts - download - - - - Cancel a pending or in process texture request - - The texture assets unique ID - - - - Master Download Thread, Queues up downloads in the threadpool - - - - - The worker thread that sends the request and handles timeouts - - A object containing the request details - - - - Handle responses from the simulator that tell us a texture we have requested is unable to be located - or no longer exists. This will remove the request from the pipeline and free up a slot if one is in use - - The sender - The EventArgs object containing the packet data - - - - Handles the remaining Image data that did not fit in the initial ImageData packet - - The sender - The EventArgs object containing the packet data - - - - Handle the initial ImageDataPacket sent from the simulator - - The sender - The EventArgs object containing the packet data - - - Current number of pending and in-process transfers - - - - A request task containing information and status of a request as it is processed through the - - - - The current which identifies the current status of the request - - - The Unique Request ID, This is also the Asset ID of the texture being requested - - - The slot this request is occupying in the threadpoolSlots array - - - The ImageType of the request. - - - The callback to fire when the request is complete, will include - the and the - object containing the result data - - - If true, indicates the callback will be fired whenever new data is returned from the simulator. - This is used to progressively render textures as portions of the texture are received. - - - An object that maintains the data of an request thats in-process. - - - - - - - - - An instance of DelegateWrapper which calls InvokeWrappedDelegate, - which in turn calls the DynamicInvoke method of the wrapped - delegate - - - - - Callback used to call EndInvoke on the asynchronously - invoked DelegateWrapper - - - - - Executes the specified delegate with the specified arguments - asynchronously on a thread pool thread - - - - - - - Invokes the wrapped delegate synchronously - - - - - - - Calls EndInvoke on the wrapper and Close on the resulting WaitHandle - to prevent resource leaks - - - - - - Delegate to wrap another delegate and its arguments - - - - - - - - - - - - - - - - - - Thrown when a packet could not be successfully deserialized @@ -19011,6 +6133,9 @@ each block containing one or more fields + + Current length of the data in this packet + Create a block from a byte array @@ -19029,9 +6154,6 @@ This will point to the position directly after the end of the serialized block when the call returns - - Current length of the data in this packet - A generic value, not an actual packet type @@ -20397,6 +7519,9 @@ + + + @@ -22455,6 +9580,11953 @@ + + Origin position of this coordinate frame + + + X axis of this coordinate frame, or Forward/At in grid terms + + + Y axis of this coordinate frame, or Left in grid terms + + + Z axis of this coordinate frame, or Up in grid terms + + + + + + Looking direction, must be a normalized vector + Up direction, must be a normalized vector + + + + Align the coordinate frame X and Y axis with a given rotation + around the Z axis in radians + + Absolute rotation around the Z axis in + radians + + + + Access to the data server which allows searching for land, events, people, etc + + + + Classified Ad categories + + + Classified is listed in the Any category + + + Classified is shopping related + + + Classified is + + + + + + + + + + + + + + + + + + + + + + + + Event Categories + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Query Flags used in many of the DirectoryManager methods to specify which query to execute and how to return the results. + + Flags can be combined using the | (pipe) character, not all flags are available in all queries + + + + Query the People database + + + + + + + + + Query the Groups database + + + Query the Events database + + + Query the land holdings database for land owned by the currently connected agent + + + + + + Query the land holdings database for land which is owned by a Group + + + Specifies the query should pre sort the results based upon traffic + when searching the Places database + + + + + + + + + + + + + + + Specifies the query should pre sort the results in an ascending order when searching the land sales database. + This flag is only used when searching the land sales database + + + Specifies the query should pre sort the results using the SalePrice field when searching the land sales database. + This flag is only used when searching the land sales database + + + Specifies the query should pre sort the results by calculating the average price/sq.m (SalePrice / Area) when searching the land sales database. + This flag is only used when searching the land sales database + + + Specifies the query should pre sort the results using the ParcelSize field when searching the land sales database. + This flag is only used when searching the land sales database + + + Specifies the query should pre sort the results using the Name field when searching the land sales database. + This flag is only used when searching the land sales database + + + When set, only parcels less than the specified Price will be included when searching the land sales database. + This flag is only used when searching the land sales database + + + When set, only parcels greater than the specified Size will be included when searching the land sales database. + This flag is only used when searching the land sales database + + + + + + + + + Include PG land in results. This flag is used when searching both the Groups, Events and Land sales databases + + + Include Mature land in results. This flag is used when searching both the Groups, Events and Land sales databases + + + Include Adult land in results. This flag is used when searching both the Groups, Events and Land sales databases + + + + + + + Land types to search dataserver for + + + + Search Auction, Mainland and Estate + + + Land which is currently up for auction + + + Parcels which are on the mainland (Linden owned) continents + + + Parcels which are on privately owned simulators + + + + The content rating of the event + + + + Event is PG + + + Event is Mature + + + Event is Adult + + + + Classified Ad Options + + There appear to be two formats the flags are packed in. + This set of flags is for the newer style + + + + + + + + + + + + + + + + + + + Classified ad query options + + + + Include all ads in results + + + Include PG ads in results + + + Include Mature ads in results + + + Include Adult ads in results + + + + The For Sale flag in PlacesReplyData + + + + Parcel is not listed for sale + + + Parcel is For Sale + + + + A classified ad on the grid + + + + UUID for this ad, useful for looking up detailed + information about it + + + The title of this classified ad + + + Flags that show certain options applied to the classified + + + Creation date of the ad + + + Expiration date of the ad + + + Price that was paid for this ad + + + Print the struct data as a string + A string containing the field name, and field value + + + + A parcel retrieved from the dataserver such as results from the + "For-Sale" listings or "Places" Search + + + + The unique dataserver parcel ID + This id is used to obtain additional information from the entry + by using the method + + + A string containing the name of the parcel + + + The size of the parcel + This field is not returned for Places searches + + + The price of the parcel + This field is not returned for Places searches + + + If True, this parcel is flagged to be auctioned + + + If true, this parcel is currently set for sale + + + Parcel traffic + + + Print the struct data as a string + A string containing the field name, and field value + + + + An Avatar returned from the dataserver + + + + Online status of agent + This field appears to be obsolete and always returns false + + + The agents first name + + + The agents last name + + + The agents + + + Print the struct data as a string + A string containing the field name, and field value + + + + Response to a "Groups" Search + + + + The Group ID + + + The name of the group + + + The current number of members + + + Print the struct data as a string + A string containing the field name, and field value + + + + Parcel information returned from a request + + Represents one of the following: + A parcel of land on the grid that has its Show In Search flag set + A parcel of land owned by the agent making the request + A parcel of land owned by a group the agent making the request is a member of + + + In a request for Group Land, the First record will contain an empty record + + Note: This is not the same as searching the land for sale data source + + + + The ID of the Agent of Group that owns the parcel + + + The name + + + The description + + + The Size of the parcel + + + The billable Size of the parcel, for mainland + parcels this will match the ActualArea field. For Group owned land this will be 10 percent smaller + than the ActualArea. For Estate land this will always be 0 + + + Indicates the ForSale status of the parcel + + + The Gridwide X position + + + The Gridwide Y position + + + The Z position of the parcel, or 0 if no landing point set + + + The name of the Region the parcel is located in + + + The Asset ID of the parcels Snapshot texture + + + The calculated visitor traffic + + + The billing product SKU + Known values are: + + 023Mainland / Full Region + 024Estate / Full Region + 027Estate / Openspace + 029Estate / Homestead + 129Mainland / Homestead (Linden Owned) + + + + + No longer used, will always be 0 + + + Get a SL URL for the parcel + A string, containing a standard SLURL + + + Print the struct data as a string + A string containing the field name, and field value + + + + An "Event" Listing summary + + + + The ID of the event creator + + + The name of the event + + + The events ID + + + A string containing the short date/time the event will begin + + + The event start time in Unixtime (seconds since epoch) + + + The events maturity rating + + + Print the struct data as a string + A string containing the field name, and field value + + + + The details of an "Event" + + + + The events ID + + + The ID of the event creator + + + The name of the event + + + The category + + + The events description + + + The short date/time the event will begin + + + The event start time in Unixtime (seconds since epoch) UTC adjusted + + + The length of the event in minutes + + + 0 if no cover charge applies + + + The cover charge amount in L$ if applicable + + + The name of the region where the event is being held + + + The gridwide location of the event + + + The maturity rating + + + Get a SL URL for the parcel where the event is hosted + A string, containing a standard SLURL + + + Print the struct data as a string + A string containing the field name, and field value + + + The event subscribers. null if no subcribers + + + Raises the EventInfoReply event + An EventInfoReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the DirEventsReply event + An DirEventsReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the PlacesReply event + A PlacesReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the DirPlacesReply event + A DirPlacesReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the DirClassifiedsReply event + A DirClassifiedsReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the DirGroupsReply event + A DirGroupsReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the DirPeopleReply event + A DirPeopleReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the DirLandReply event + A DirLandReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + + Constructs a new instance of the DirectoryManager class + + An instance of GridClient + + + + Query the data server for a list of classified ads containing the specified string. + Defaults to searching for classified placed in any category, and includes PG, Adult and Mature + results. + + Responses are sent 16 per response packet, there is no way to know how many results a query reply will contain however assuming + the reply packets arrived ordered, a response with less than 16 entries would indicate all results have been received + + The event is raised when a response is received from the simulator + + A string containing a list of keywords to search for + A UUID to correlate the results when the event is raised + + + + Query the data server for a list of classified ads which contain specified keywords (Overload) + + The event is raised when a response is received from the simulator + + A string containing a list of keywords to search for + The category to search + A set of flags which can be ORed to modify query options + such as classified maturity rating. + A UUID to correlate the results when the event is raised + + Search classified ads containing the key words "foo" and "bar" in the "Any" category that are either PG or Mature + + UUID searchID = StartClassifiedSearch("foo bar", ClassifiedCategories.Any, ClassifiedQueryFlags.PG | ClassifiedQueryFlags.Mature); + + + + Responses are sent 16 at a time, there is no way to know how many results a query reply will contain however assuming + the reply packets arrived ordered, a response with less than 16 entries would indicate all results have been received + + + + + Starts search for places (Overloaded) + + The event is raised when a response is received from the simulator + + Search text + Each request is limited to 100 places + being returned. To get the first 100 result entries of a request use 0, + from 100-199 use 1, 200-299 use 2, etc. + A UUID to correlate the results when the event is raised + + + + Queries the dataserver for parcels of land which are flagged to be shown in search + + The event is raised when a response is received from the simulator + + A string containing a list of keywords to search for separated by a space character + A set of flags which can be ORed to modify query options + such as classified maturity rating. + The category to search + Each request is limited to 100 places + being returned. To get the first 100 result entries of a request use 0, + from 100-199 use 1, 200-299 use 2, etc. + A UUID to correlate the results when the event is raised + + Search places containing the key words "foo" and "bar" in the "Any" category that are either PG or Adult + + UUID searchID = StartDirPlacesSearch("foo bar", DirFindFlags.DwellSort | DirFindFlags.IncludePG | DirFindFlags.IncludeAdult, ParcelCategory.Any, 0); + + + + Additional information on the results can be obtained by using the ParcelManager.InfoRequest method + + + + + Starts a search for land sales using the directory + + The event is raised when a response is received from the simulator + + What type of land to search for. Auction, + estate, mainland, "first land", etc + The OnDirLandReply event handler must be registered before + calling this function. There is no way to determine how many + results will be returned, or how many times the callback will be + fired other than you won't get more than 100 total parcels from + each query. + + + + Starts a search for land sales using the directory + + The event is raised when a response is received from the simulator + + What type of land to search for. Auction, + estate, mainland, "first land", etc + Maximum price to search for + Maximum area to search for + Each request is limited to 100 parcels + being returned. To get the first 100 parcels of a request use 0, + from 100-199 use 1, 200-299 use 2, etc. + The OnDirLandReply event handler must be registered before + calling this function. There is no way to determine how many + results will be returned, or how many times the callback will be + fired other than you won't get more than 100 total parcels from + each query. + + + + Send a request to the data server for land sales listings + + + Flags sent to specify query options + + Available flags: + Specify the parcel rating with one or more of the following: + IncludePG IncludeMature IncludeAdult + + Specify the field to pre sort the results with ONLY ONE of the following: + PerMeterSort NameSort AreaSort PricesSort + + Specify the order the results are returned in, if not specified the results are pre sorted in a Descending Order + SortAsc + + Specify additional filters to limit the results with one or both of the following: + LimitByPrice LimitByArea + + Flags can be combined by separating them with the | (pipe) character + + Additional details can be found in + + What type of land to search for. Auction, + Estate or Mainland + Maximum price to search for when the + DirFindFlags.LimitByPrice flag is specified in findFlags + Maximum area to search for when the + DirFindFlags.LimitByArea flag is specified in findFlags + Each request is limited to 100 parcels + being returned. To get the first 100 parcels of a request use 0, + from 100-199 use 100, 200-299 use 200, etc. + The event will be raised with the response from the simulator + + There is no way to determine how many results will be returned, or how many times the callback will be + fired other than you won't get more than 100 total parcels from + each reply. + + Any land set for sale to either anybody or specific to the connected agent will be included in the + results if the land is included in the query + + + // request all mainland, any maturity rating that is larger than 512 sq.m + StartLandSearch(DirFindFlags.SortAsc | DirFindFlags.PerMeterSort | DirFindFlags.LimitByArea | DirFindFlags.IncludePG | DirFindFlags.IncludeMature | DirFindFlags.IncludeAdult, SearchTypeFlags.Mainland, 0, 512, 0); + + + + + Search for Groups + + The name or portion of the name of the group you wish to search for + Start from the match number + + + + + Search for Groups + + The name or portion of the name of the group you wish to search for + Start from the match number + Search flags + + + + + Search the People directory for other avatars + + The name or portion of the name of the avatar you wish to search for + + + + + + Search Places for parcels of land you personally own + + + + + Searches Places for land owned by the specified group + + ID of the group you want to recieve land list for (You must be a member of the group) + Transaction (Query) ID which can be associated with results from your request. + + + + Search the Places directory for parcels that are listed in search and contain the specified keywords + + A string containing the keywords to search for + Transaction (Query) ID which can be associated with results from your request. + + + + Search Places - All Options + + One of the Values from the DirFindFlags struct, ie: AgentOwned, GroupOwned, etc. + One of the values from the SearchCategory Struct, ie: Any, Linden, Newcomer + A string containing a list of keywords to search for separated by a space character + String Simulator Name to search in + LLUID of group you want to recieve results for + Transaction (Query) ID which can be associated with results from your request. + Transaction (Query) ID which can be associated with results from your request. + + + + Search All Events with specifid searchText in all categories, includes PG, Mature and Adult + + A string containing a list of keywords to search for separated by a space character + Each request is limited to 100 entries + being returned. To get the first group of entries of a request use 0, + from 100-199 use 100, 200-299 use 200, etc. + UUID of query to correlate results in callback. + + + + Search Events + + A string containing a list of keywords to search for separated by a space character + One or more of the following flags: DateEvents, IncludePG, IncludeMature, IncludeAdult + from the Enum + + Multiple flags can be combined by separating the flags with the | (pipe) character + "u" for in-progress and upcoming events, -or- number of days since/until event is scheduled + For example "0" = Today, "1" = tomorrow, "2" = following day, "-1" = yesterday, etc. + Each request is limited to 100 entries + being returned. To get the first group of entries of a request use 0, + from 100-199 use 100, 200-299 use 200, etc. + EventCategory event is listed under. + UUID of query to correlate results in callback. + + + Requests Event Details + ID of Event returned from the method + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming event message + The Unique Capabilities Key + The event message containing the data + The simulator the message originated from + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming event message + The Unique Capabilities Key + The event message containing the data + The simulator the message originated from + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Contains the Event data returned from the data server from an EventInfoRequest + + + + A single EventInfo object containing the details of an event + + + + Construct a new instance of the EventInfoReplyEventArgs class + A single EventInfo object containing the details of an event + + + Contains the "Event" detail data returned from the data server + + + The ID returned by + + + A list of "Events" returned by the data server + + + Construct a new instance of the DirEventsReplyEventArgs class + The ID of the query returned by the data server. + This will correlate to the ID returned by the method + A list containing the "Events" returned by the search query + + + Contains the "Event" list data returned from the data server + + + The ID returned by + + + A list of "Places" returned by the data server + + + Construct a new instance of PlacesReplyEventArgs class + The ID of the query returned by the data server. + This will correlate to the ID returned by the method + A list containing the "Places" returned by the data server query + + + Contains the places data returned from the data server + + + The ID returned by + + + A list containing Places data returned by the data server + + + Construct a new instance of the DirPlacesReplyEventArgs class + The ID of the query returned by the data server. + This will correlate to the ID returned by the method + A list containing land data returned by the data server + + + Contains the classified data returned from the data server + + + A list containing Classified Ads returned by the data server + + + Construct a new instance of the DirClassifiedsReplyEventArgs class + A list of classified ad data returned from the data server + + + Contains the group data returned from the data server + + + The ID returned by + + + A list containing Groups data returned by the data server + + + Construct a new instance of the DirGroupsReplyEventArgs class + The ID of the query returned by the data server. + This will correlate to the ID returned by the method + A list of groups data returned by the data server + + + Contains the people data returned from the data server + + + The ID returned by + + + A list containing People data returned by the data server + + + Construct a new instance of the DirPeopleReplyEventArgs class + The ID of the query returned by the data server. + This will correlate to the ID returned by the method + A list of people data returned by the data server + + + Contains the land sales data returned from the data server + + + A list containing land forsale data returned by the data server + + + Construct a new instance of the DirLandReplyEventArgs class + A list of parcels for sale returned by the data server + + + + Represends individual HTTP Download request + + + + URI of the item to fetch + + + Timout specified in milliseconds + + + Download progress callback + + + Download completed callback + + + Accept the following content type + + + How many times will this request be retried + + + Current fetch attempt + + + Default constructor + + + Constructor + + + + Manages async HTTP downloads with a limit on maximum + concurrent downloads + + + + Maximum number of parallel downloads from a single endpoint + + + Client certificate + + + Default constructor + + + Cleanup method + + + Setup http download request + + + Check the queue for pending work + + + Enqueue a new HTTP download + + + Describes tasks returned in LandStatReply + + + + Estate level administration and utilities + + + + Textures for each of the four terrain height levels + + + Upper/lower texture boundaries for each corner of the sim + + + + Constructor for EstateTools class + + + + + Used in the ReportType field of a LandStatRequest + + + Used by EstateOwnerMessage packets + + + Used by EstateOwnerMessage packets + + + + + + + + No flags set + + + Only return targets scripted objects + + + Only return targets objects if on others land + + + Returns target's scripted objects and objects on other parcels + + + Ground texture settings for each corner of the region + + + Used by GroundTextureHeightSettings + + + The high and low texture thresholds for each corner of the sim + + + The event subscribers. null if no subcribers + + + Raises the TopCollidersReply event + A TopCollidersReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the TopScriptsReply event + A TopScriptsReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the EstateUsersReply event + A EstateUsersReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the EstateGroupsReply event + A EstateGroupsReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the EstateManagersReply event + A EstateManagersReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the EstateBansReply event + A EstateBansReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the EstateCovenantReply event + A EstateCovenantReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + The event subscribers. null if no subcribers + + + Raises the EstateUpdateInfoReply event + A EstateUpdateInfoReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the data server responds to a request. + + + + Requests estate information such as top scripts and colliders + + + + + + + + Requests estate settings, including estate manager and access/ban lists + + + Requests the "Top Scripts" list for the current region + + + Requests the "Top Colliders" list for the current region + + + + Set several estate specific configuration variables + + The Height of the waterlevel over the entire estate. Defaults to 20 + The maximum height change allowed above the baked terrain. Defaults to 4 + The minimum height change allowed below the baked terrain. Defaults to -4 + true to use + if True forces the sun position to the position in SunPosition + The current position of the sun on the estate, or when FixedSun is true the static position + the sun will remain. 6.0 = Sunrise, 30.0 = Sunset + + + + Request return of objects owned by specified avatar + + The Agents owning the primitives to return + specify the coverage and type of objects to be included in the return + true to perform return on entire estate + + + + + + + + + Used for setting and retrieving various estate panel settings + + EstateOwnerMessage Method field + List of parameters to include + + + + Kick an avatar from an estate + + Key of Agent to remove + + + + Ban an avatar from an estate + Key of Agent to remove + Ban user from this estate and all others owned by the estate owner + + + Unban an avatar from an estate + Key of Agent to remove + /// Unban user from this estate and all others owned by the estate owner + + + + Send a message dialog to everyone in an entire estate + + Message to send all users in the estate + + + + Send a message dialog to everyone in a simulator + + Message to send all users in the simulator + + + + Send an avatar back to their home location + + Key of avatar to send home + + + + Begin the region restart process + + + + + Cancels a region restart + + + + Estate panel "Region" tab settings + + + Estate panel "Debug" tab settings + + + Used for setting the region's terrain textures for its four height levels + + + + + + + Used for setting sim terrain texture heights + + + Requests the estate covenant + + + + Upload a terrain RAW file + + A byte array containing the encoded terrain data + The name of the file being uploaded + The Id of the transfer request + + + + Teleports all users home in current Estate + + + + + Remove estate manager + Key of Agent to Remove + removes manager to this estate and all others owned by the estate owner + + + + Add estate manager + Key of Agent to Add + Add agent as manager to this estate and all others owned by the estate owner + + + + Add's an agent to the estate Allowed list + Key of Agent to Add + Add agent as an allowed reisdent to All estates if true + + + + Removes an agent from the estate Allowed list + Key of Agent to Remove + Removes agent as an allowed reisdent from All estates if true + + + + + Add's a group to the estate Allowed list + Key of Group to Add + Add Group as an allowed group to All estates if true + + + + + Removes a group from the estate Allowed list + Key of Group to Remove + Removes Group as an allowed Group from All estates if true + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Raised on LandStatReply when the report type is for "top colliders" + + + + The number of returned items in LandStatReply + + + + + A Dictionary of Object UUIDs to tasks returned in LandStatReply + + + + Construct a new instance of the TopCollidersReplyEventArgs class + The number of returned items in LandStatReply + Dictionary of Object UUIDs to tasks returned in LandStatReply + + + Raised on LandStatReply when the report type is for "top Scripts" + + + + The number of scripts returned in LandStatReply + + + + + A Dictionary of Object UUIDs to tasks returned in LandStatReply + + + + Construct a new instance of the TopScriptsReplyEventArgs class + The number of returned items in LandStatReply + Dictionary of Object UUIDs to tasks returned in LandStatReply + + + Returned, along with other info, upon a successful .RequestInfo() + + + + The identifier of the estate + + + + + The number of returned itmes + + + + + List of UUIDs of Banned Users + + + + Construct a new instance of the EstateBansReplyEventArgs class + The estate's identifier on the grid + The number of returned items in LandStatReply + User UUIDs banned + + + Returned, along with other info, upon a successful .RequestInfo() + + + + The identifier of the estate + + + + + The number of returned items + + + + + List of UUIDs of Allowed Users + + + + Construct a new instance of the EstateUsersReplyEventArgs class + The estate's identifier on the grid + The number of users + Allowed users UUIDs + + + Returned, along with other info, upon a successful .RequestInfo() + + + + The identifier of the estate + + + + + The number of returned items + + + + + List of UUIDs of Allowed Groups + + + + Construct a new instance of the EstateGroupsReplyEventArgs class + The estate's identifier on the grid + The number of Groups + Allowed Groups UUIDs + + + Returned, along with other info, upon a successful .RequestInfo() + + + + The identifier of the estate + + + + + The number of returned items + + + + + List of UUIDs of the Estate's Managers + + + + Construct a new instance of the EstateManagersReplyEventArgs class + The estate's identifier on the grid + The number of Managers + Managers UUIDs + + + Returned, along with other info, upon a successful .RequestInfo() + + + + The Covenant + + + + + The timestamp + + + + + The Estate name + + + + + The Estate Owner's ID (can be a GroupID) + + + + Construct a new instance of the EstateCovenantReplyEventArgs class + The Covenant ID + The timestamp + The estate's name + The Estate Owner's ID (can be a GroupID) + + + Returned, along with other info, upon a successful .RequestInfo() + + + + The estate's name + + + + + The Estate Owner's ID (can be a GroupID) + + + + + The identifier of the estate on the grid + + + + + + + Construct a new instance of the EstateUpdateInfoReplyEventArgs class + The estate's name + The Estate Owners ID (can be a GroupID) + The estate's identifier on the grid + + + + + Registers, unregisters, and fires events generated by incoming packets + + + + + Object that is passed to worker threads in the ThreadPool for + firing packet callbacks + + + + Callback to fire for this packet + + + Reference to the simulator that this packet came from + + + The packet that needs to be processed + + + Reference to the GridClient object + + + + Default constructor + + + + + + Register an event handler + + Use PacketType.Default to fire this event on every + incoming packet + Packet type to register the handler for + Callback to be fired + True if this callback should be ran + asynchronously, false to run it synchronous + + + + Unregister an event handler + + Packet type to unregister the handler for + Callback to be unregistered + + + + Fire the events registered for this packet type + + Incoming packet type + Incoming packet + Simulator this packet was received from + + + + Registers, unregisters, and fires events generated by the Capabilities + event queue + + + + + Object that is passed to worker threads in the ThreadPool for + firing CAPS callbacks + + + + Callback to fire for this packet + + + Name of the CAPS event + + + Strongly typed decoded data + + + Reference to the simulator that generated this event + + + Reference to the GridClient object + + + + Default constructor + + Reference to the GridClient object + + + + Register an new event handler for a capabilities event sent via the EventQueue + + Use String.Empty to fire this event on every CAPS event + Capability event name to register the + handler for + Callback to fire + + + + Unregister a previously registered capabilities handler + + Capability event name unregister the + handler for + Callback to unregister + + + + Fire the events registered for this event type synchronously + + Capability name + Decoded event body + Reference to the simulator that + generated this event + + + + Fire the events registered for this event type asynchronously + + Capability name + Decoded event body + Reference to the simulator that + generated this event + + + + + + + + The avatar has no rights + + + The avatar can see the online status of the target avatar + + + The avatar can see the location of the target avatar on the map + + + The avatar can modify the ojects of the target avatar + + + + This class holds information about an avatar in the friends list. There are two ways + to interface to this class. The first is through the set of boolean properties. This is the typical + way clients of this class will use it. The second interface is through two bitflag properties, + TheirFriendsRights and MyFriendsRights + + + + + System ID of the avatar + + + + + full name of the avatar + + + + + True if the avatar is online + + + + + True if the friend can see if I am online + + + + + True if the friend can see me on the map + + + + + True if the freind can modify my objects + + + + + True if I can see if my friend is online + + + + + True if I can see if my friend is on the map + + + + + True if I can modify my friend's objects + + + + + My friend's rights represented as bitmapped flags + + + + + My rights represented as bitmapped flags + + + + + Used internally when building the initial list of friends at login time + + System ID of the avatar being prepesented + Rights the friend has to see you online and to modify your objects + Rights you have to see your friend online and to modify their objects + + + + FriendInfo represented as a string + + A string reprentation of both my rights and my friends rights + + + + This class is used to add and remove avatars from your friends list and to manage their permission. + + + + The event subscribers. null if no subcribers + + + Raises the FriendOnline event + A FriendInfoEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the simulator sends notification one of the members in our friends list comes online + + + The event subscribers. null if no subcribers + + + Raises the FriendOffline event + A FriendInfoEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the simulator sends notification one of the members in our friends list goes offline + + + The event subscribers. null if no subcribers + + + Raises the FriendRightsUpdate event + A FriendInfoEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the simulator sends notification one of the members in our friends list grants or revokes permissions + + + The event subscribers. null if no subcribers + + + Raises the FriendNames event + A FriendNamesEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the simulator sends us the names on our friends list + + + The event subscribers. null if no subcribers + + + Raises the FriendshipOffered event + A FriendshipOfferedEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the simulator sends notification another agent is offering us friendship + + + The event subscribers. null if no subcribers + + + Raises the FriendshipResponse event + A FriendshipResponseEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when a request we sent to friend another agent is accepted or declined + + + The event subscribers. null if no subcribers + + + Raises the FriendshipTerminated event + A FriendshipTerminatedEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the simulator sends notification one of the members in our friends list has terminated + our friendship + + + The event subscribers. null if no subcribers + + + Raises the FriendFoundReply event + A FriendFoundReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Raised when the simulator sends the location of a friend we have + requested map location info for + + + + A dictionary of key/value pairs containing known friends of this avatar. + + The Key is the of the friend, the value is a + object that contains detailed information including permissions you have and have given to the friend + + + + + A Dictionary of key/value pairs containing current pending frienship offers. + + The key is the of the avatar making the request, + the value is the of the request which is used to accept + or decline the friendship offer + + + + + Internal constructor + + A reference to the GridClient Object + + + + Accept a friendship request + + agentID of avatatar to form friendship with + imSessionID of the friendship request message + + + + Decline a friendship request + + of friend + imSessionID of the friendship request message + + + + Overload: Offer friendship to an avatar. + + System ID of the avatar you are offering friendship to + + + + Offer friendship to an avatar. + + System ID of the avatar you are offering friendship to + A message to send with the request + + + + Terminate a friendship with an avatar + + System ID of the avatar you are terminating the friendship with + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + + Change the rights of a friend avatar. + + the of the friend + the new rights to give the friend + This method will implicitly set the rights to those passed in the rights parameter. + + + + Use to map a friends location on the grid. + + Friends UUID to find + + + + + Use to track a friends movement on the grid + + Friends Key + + + + Ask for a notification of friend's online status + + Friend's UUID + + + + This handles the asynchronous response of a RequestAvatarNames call. + + + names cooresponding to the the list of IDs sent the the RequestAvatarNames call. + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + + Populate FriendList with data from the login reply + + true if login was successful + true if login request is requiring a redirect + A string containing the response to the login request + A string containing the reason for the request + A object containing the decoded + reply from the login server + + + Contains information on a member of our friends list + + + Get the FriendInfo + + + + Construct a new instance of the FriendInfoEventArgs class + + The FriendInfo + + + Contains Friend Names + + + A dictionary where the Key is the ID of the Agent, + and the Value is a string containing their name + + + + Construct a new instance of the FriendNamesEventArgs class + + A dictionary where the Key is the ID of the Agent, + and the Value is a string containing their name + + + Sent when another agent requests a friendship with our agent + + + Get the ID of the agent requesting friendship + + + Get the name of the agent requesting friendship + + + Get the ID of the session, used in accepting or declining the + friendship offer + + + + Construct a new instance of the FriendshipOfferedEventArgs class + + The ID of the agent requesting friendship + The name of the agent requesting friendship + The ID of the session, used in accepting or declining the + friendship offer + + + A response containing the results of our request to form a friendship with another agent + + + Get the ID of the agent we requested a friendship with + + + Get the name of the agent we requested a friendship with + + + true if the agent accepted our friendship offer + + + + Construct a new instance of the FriendShipResponseEventArgs class + + The ID of the agent we requested a friendship with + The name of the agent we requested a friendship with + true if the agent accepted our friendship offer + + + Contains data sent when a friend terminates a friendship with us + + + Get the ID of the agent that terminated the friendship with us + + + Get the name of the agent that terminated the friendship with us + + + + Construct a new instance of the FrindshipTerminatedEventArgs class + + The ID of the friend who terminated the friendship with us + The name of the friend who terminated the friendship with us + + + + Data sent in response to a request which contains the information to allow us to map the friends location + + + + Get the ID of the agent we have received location information for + + + Get the region handle where our mapped friend is located + + + Get the simulator local position where our friend is located + + + + Construct a new instance of the FriendFoundReplyEventArgs class + + The ID of the agent we have requested location information for + The region handle where our friend is located + The simulator local position our friend is located + + + + Main class to expose grid functionality to clients. All of the + classes needed for sending and receiving data are accessible through + this class. + + + + // Example minimum code required to instantiate class and + // connect to a simulator. + using System; + using System.Collections.Generic; + using System.Text; + using OpenMetaverse; + + namespace FirstBot + { + class Bot + { + public static GridClient Client; + static void Main(string[] args) + { + Client = new GridClient(); // instantiates the GridClient class + // to the global Client object + // Login to Simulator + Client.Network.Login("FirstName", "LastName", "Password", "FirstBot", "1.0"); + // Wait for a Keypress + Console.ReadLine(); + // Logout of simulator + Client.Network.Logout(); + } + } + } + + + + + Networking subsystem + + + Settings class including constant values and changeable + parameters for everything + + + Parcel (subdivided simulator lots) subsystem + + + Our own avatars subsystem + + + Other avatars subsystem + + + Estate subsystem + + + Friends list subsystem + + + Grid (aka simulator group) subsystem + + + Object subsystem + + + Group subsystem + + + Asset subsystem + + + Appearance subsystem + + + Inventory subsystem + + + Directory searches including classifieds, people, land + sales, etc + + + Handles land, wind, and cloud heightmaps + + + Handles sound-related networking + + + Throttling total bandwidth usage, or allocating bandwidth + for specific data stream types + + + + Default constructor + + + + + Return the full name of this instance + + Client avatars full name + + + + Map layer request type + + + + Objects and terrain are shown + + + Only the terrain is shown, no objects + + + Overlay showing land for sale and for auction + + + + Type of grid item, such as telehub, event, populator location, etc. + + + + Telehub + + + PG rated event + + + Mature rated event + + + Popular location + + + Locations of avatar groups in a region + + + Land for sale + + + Classified ad + + + Adult rated event + + + Adult land for sale + + + + Information about a region on the grid map + + + + Sim X position on World Map + + + Sim Y position on World Map + + + Sim Name (NOTE: In lowercase!) + + + + + + Appears to always be zero (None) + + + Sim's defined Water Height + + + + + + UUID of the World Map image + + + Unique identifier for this region, a combination of the X + and Y position + + + + + + + + + + + + + + + + + + + + + + + Visual chunk of the grid map + + + + + Base class for Map Items + + + + The Global X position of the item + + + The Global Y position of the item + + + Get the Local X position of the item + + + Get the Local Y position of the item + + + Get the Handle of the region + + + + Represents an agent or group of agents location + + + + + Represents a Telehub location + + + + + Represents a non-adult parcel of land for sale + + + + + Represents an Adult parcel of land for sale + + + + + Represents a PG Event + + + + + Represents a Mature event + + + + + Represents an Adult event + + + + + Manages grid-wide tasks such as the world map + + + + The event subscribers. null if no subcribers + + + Raises the CoarseLocationUpdate event + A CoarseLocationUpdateEventArgs object containing the + data sent by simulator + + + Thread sync lock object + + + Raised when the simulator sends a + containing the location of agents in the simulator + + + The event subscribers. null if no subcribers + + + Raises the GridRegion event + A GridRegionEventArgs object containing the + data sent by simulator + + + Thread sync lock object + + + Raised when the simulator sends a Region Data in response to + a Map request + + + The event subscribers. null if no subcribers + + + Raises the GridLayer event + A GridLayerEventArgs object containing the + data sent by simulator + + + Thread sync lock object + + + Raised when the simulator sends GridLayer object containing + a map tile coordinates and texture information + + + The event subscribers. null if no subcribers + + + Raises the GridItems event + A GridItemEventArgs object containing the + data sent by simulator + + + Thread sync lock object + + + Raised when the simulator sends GridItems object containing + details on events, land sales at a specific location + + + The event subscribers. null if no subcribers + + + Raises the RegionHandleReply event + A RegionHandleReplyEventArgs object containing the + data sent by simulator + + + Thread sync lock object + + + Raised in response to a Region lookup + + + Unknown + + + Current direction of the sun + + + Current angular velocity of the sun + + + Microseconds since the start of SL 4-hour day + + + A dictionary of all the regions, indexed by region name + + + A dictionary of all the regions, indexed by region handle + + + + Constructor + + Instance of GridClient object to associate with this GridManager instance + + + + + + + + + + Request a map layer + + The name of the region + The type of layer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Request data for all mainland (Linden managed) simulators + + + + + Request the region handle for the specified region UUID + + UUID of the region to look up + + + + Get grid region information using the region name, this function + will block until it can find the region or gives up + + Name of sim you're looking for + Layer that you are requesting + Will contain a GridRegion for the sim you're + looking for if successful, otherwise an empty structure + True if the GridRegion was successfully fetched, otherwise + false + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + + Avatar group management + + + + Key of Group Member + + + Total land contribution + + + Online status information + + + Abilities that the Group Member has + + + Current group title + + + Is a group owner + + + + Role manager for a group + + + + Key of the group + + + Key of Role + + + Name of Role + + + Group Title associated with Role + + + Description of Role + + + Abilities Associated with Role + + + Returns the role's title + The role's title + + + + Class to represent Group Title + + + + Key of the group + + + ID of the role title belongs to + + + Group Title + + + Whether title is Active + + + Returns group title + + + + Represents a group on the grid + + + + Key of Group + + + Key of Group Insignia + + + Key of Group Founder + + + Key of Group Role for Owners + + + Name of Group + + + Text of Group Charter + + + Title of "everyone" role + + + Is the group open for enrolement to everyone + + + Will group show up in search + + + + + + + + + + + + Is the group Mature + + + Cost of group membership + + + + + + + + + The total number of current members this group has + + + The number of roles this group has configured + + + Show this group in agent's profile + + + Returns the name of the group + A string containing the name of the group + + + + A group Vote + + + + Key of Avatar who created Vote + + + Text of the Vote proposal + + + Total number of votes + + + + A group proposal + + + + The Text of the proposal + + + The minimum number of members that must vote before proposal passes or failes + + + The required ration of yes/no votes required for vote to pass + The three options are Simple Majority, 2/3 Majority, and Unanimous + TODO: this should be an enum + + + The duration in days votes are accepted + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Struct representing a group notice + + + + + + + + + + + + + + + + + + + + + + + Struct representing a group notice list entry + + + + Notice ID + + + Creation timestamp of notice + + + Agent name who created notice + + + Notice subject + + + Is there an attachment? + + + Attachment Type + + + + Struct representing a member of a group chat session and their settings + + + + The of the Avatar + + + True if user has voice chat enabled + + + True of Avatar has moderator abilities + + + True if a moderator has muted this avatars chat + + + True if a moderator has muted this avatars voice + + + + Role update flags + + + + + + + + + + + + + + + + + + + + + + + + + Can send invitations to groups default role + + + Can eject members from group + + + Can toggle 'Open Enrollment' and change 'Signup fee' + + + Member is visible in the public member list + + + Can create new roles + + + Can delete existing roles + + + Can change Role names, titles and descriptions + + + Can assign other members to assigners role + + + Can assign other members to any role + + + Can remove members from roles + + + Can assign and remove abilities in roles + + + Can change group Charter, Insignia, 'Publish on the web' and which + members are publicly visible in group member listings + + + Can buy land or deed land to group + + + Can abandon group owned land to Governor Linden on mainland, or Estate owner for + private estates + + + Can set land for-sale information on group owned parcels + + + Can subdivide and join parcels + + + Can change music and media settings + + + Can toggle 'Edit Terrain' option in Land settings + + + Can toggle various About Land > Options settings + + + Can toggle "Show in Find Places" and set search category + + + Can change parcel name, description, and 'Publish on web' settings + + + Can set the landing point and teleport routing on group land + + + Can always terraform land, even if parcel settings have it turned off + + + Can always fly while over group owned land + + + Can always rez objects on group owned land + + + Can always create landmarks for group owned parcels + + + Can set home location on any group owned parcel + + + Allowed to hold events on group-owned land + + + Can modify public access settings for group owned parcels + + + Can manager parcel ban lists on group owned land + + + Can manage pass list sales information + + + Can eject and freeze other avatars on group owned land + + + Can return objects set to group + + + Can return non-group owned/set objects + + + Can return group owned objects + + + Can landscape using Linden plants + + + Can deed objects to group + + + Can move group owned objects + + + Can set group owned objects for-sale + + + Pay group liabilities and receive group dividends + + + Can send group notices + + + Can receive group notices + + + Can create group proposals + + + Can vote on group proposals + + + Can join group chat sessions + + + Can use voice chat in Group Chat sessions + + + Can moderate group chat sessions + + + Has admin rights to any experiences owned by this group + + + Can sign scripts for experiences owned by this group + + + Allows access to ban / un-ban agents from a group + + + + Ban actions available for group members + + + + Ban agent from joining a group + + + Remove restriction on agent jointing a group + + + + Handles all network traffic related to reading and writing group + information + + + + The event subscribers. null if no subcribers + + + Raises the CurrentGroups event + A CurrentGroupsEventArgs object containing the + data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + our current group membership + + + The event subscribers. null if no subcribers + + + Raises the GroupNamesReply event + A GroupNamesEventArgs object containing the + data response from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a RequestGroupName + or RequestGroupNames request + + + The event subscribers. null if no subcribers + + + Raises the GroupProfile event + An GroupProfileEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the GroupMembers event + A GroupMembersEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the GroupRolesDataReply event + A GroupRolesDataReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the GroupRoleMembersReply event + A GroupRolesRoleMembersReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the GroupTitlesReply event + A GroupTitlesReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the GroupAccountSummary event + A GroupAccountSummaryReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when a response to a RequestGroupAccountSummary is returned + by the simulator + + + The event subscribers. null if no subcribers + + + Raises the GroupCreated event + An GroupCreatedEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when a request to create a group is successful + + + The event subscribers. null if no subcribers + + + Raises the GroupJoined event + A GroupOperationEventArgs object containing the + result of the operation returned from the simulator + + + Thread sync lock object + + + Raised when a request to join a group either + fails or succeeds + + + The event subscribers. null if no subcribers + + + Raises the GroupLeft event + A GroupOperationEventArgs object containing the + result of the operation returned from the simulator + + + Thread sync lock object + + + Raised when a request to leave a group either + fails or succeeds + + + The event subscribers. null if no subcribers + + + Raises the GroupDropped event + An GroupDroppedEventArgs object containing the + the group your agent left + + + Thread sync lock object + + + Raised when A group is removed from the group server + + + The event subscribers. null if no subcribers + + + Raises the GroupMemberEjected event + An GroupMemberEjectedEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when a request to eject a member from a group either + fails or succeeds + + + The event subscribers. null if no subcribers + + + Raises the GroupNoticesListReply event + An GroupNoticesListReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us group notices + + + + The event subscribers. null if no subcribers + + + Raises the GroupInvitation event + An GroupInvitationEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when another agent invites our avatar to join a group + + + The event subscribers. null if no subcribers + + + Raises the BannedAgents event + An BannedAgentsEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when another agent invites our avatar to join a group + + + A reference to the current instance + + + Currently-active group members requests + + + Currently-active group roles requests + + + Currently-active group role-member requests + + + Dictionary keeping group members while request is in progress + + + Dictionary keeping mebmer/role mapping while request is in progress + + + Dictionary keeping GroupRole information while request is in progress + + + Caches group name lookups + + + + Construct a new instance of the GroupManager class + + A reference to the current instance + + + + Request a current list of groups the avatar is a member of. + + CAPS Event Queue must be running for this to work since the results + come across CAPS. + + + + Lookup name of group based on groupID + + groupID of group to lookup name for. + + + + Request lookup of multiple group names + + List of group IDs to request. + + + Lookup group profile data such as name, enrollment, founder, logo, etc + Subscribe to OnGroupProfile event to receive the results. + group ID (UUID) + + + Request a list of group members. + Subscribe to OnGroupMembers event to receive the results. + group ID (UUID) + UUID of the request, use to index into cache + + + Request group roles + Subscribe to OnGroupRoles event to receive the results. + group ID (UUID) + UUID of the request, use to index into cache + + + Request members (members,role) role mapping for a group. + Subscribe to OnGroupRolesMembers event to receive the results. + group ID (UUID) + UUID of the request, use to index into cache + + + Request a groups Titles + Subscribe to OnGroupTitles event to receive the results. + group ID (UUID) + UUID of the request, use to index into cache + + + Begin to get the group account summary + Subscribe to the OnGroupAccountSummary event to receive the results. + group ID (UUID) + How long of an interval + Which interval (0 for current, 1 for last) + + + Invites a user to a group + The group to invite to + A list of roles to invite a person to + Key of person to invite + + + Set a group as the current active group + group ID (UUID) + + + Change the role that determines your active title + Group ID to use + Role ID to change to + + + Set this avatar's tier contribution + Group ID to change tier in + amount of tier to donate + + + + Save wheather agent wants to accept group notices and list this group in their profile + + Group + Accept notices from this group + List this group in the profile + + + Request to join a group + Subscribe to OnGroupJoined event for confirmation. + group ID (UUID) to join. + + + + Request to create a new group. If the group is successfully + created, L$100 will automatically be deducted + + Subscribe to OnGroupCreated event to receive confirmation. + Group struct containing the new group info + + + Update a group's profile and other information + Groups ID (UUID) to update. + Group struct to update. + + + Eject a user from a group + Group ID to eject the user from + Avatar's key to eject + + + Update role information + Modified role to be updated + + + Create a new group role + Group ID to update + Role to create + + + Delete a group role + Group ID to update + Role to delete + + + Remove an avatar from a role + Group ID to update + Role ID to be removed from + Avatar's Key to remove + + + Assign an avatar to a role + Group ID to update + Role ID to assign to + Avatar's ID to assign to role + + + Request the group notices list + Group ID to fetch notices for + + + Request a group notice by key + ID of group notice + + + Send out a group notice + Group ID to update + GroupNotice structure containing notice data + + + Start a group proposal (vote) + The Group ID to send proposal to + GroupProposal structure containing the proposal + + + Request to leave a group + Subscribe to OnGroupLeft event to receive confirmation + The group to leave + + + + Gets the URI of the cpability for handling group bans + + Group ID + null, if the feature is not supported, or URI of the capability + + + + Request a list of residents banned from joining a group + + UUID of the group + + + + Request a list of residents banned from joining a group + + UUID of the group + Callback on request completition + + + + Request that group of agents be banned or unbanned from the group + + Group ID + Ban/Unban action + Array of agents UUIDs to ban + + + + Request that group of agents be banned or unbanned from the group + + Group ID + Ban/Unban action + Array of agents UUIDs to ban + Callback + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Contains the current groups your agent is a member of + + + Get the current groups your agent is a member of + + + Construct a new instance of the CurrentGroupsEventArgs class + The current groups your agent is a member of + + + A Dictionary of group names, where the Key is the groups ID and the value is the groups name + + + Get the Group Names dictionary + + + Construct a new instance of the GroupNamesEventArgs class + The Group names dictionary + + + Represents the members of a group + + + Get the ID as returned by the request to correlate + this result set and the request + + + Get the ID of the group + + + Get the dictionary of members + + + + Construct a new instance of the GroupMembersReplyEventArgs class + + The ID of the request + The ID of the group + The membership list of the group + + + Represents the roles associated with a group + + + Get the ID as returned by the request to correlate + this result set and the request + + + Get the ID of the group + + + Get the dictionary containing the roles + + + Construct a new instance of the GroupRolesDataReplyEventArgs class + The ID as returned by the request to correlate + this result set and the request + The ID of the group + The dictionary containing the roles + + + Represents the Role to Member mappings for a group + + + Get the ID as returned by the request to correlate + this result set and the request + + + Get the ID of the group + + + Get the member to roles map + + + Construct a new instance of the GroupRolesMembersReplyEventArgs class + The ID as returned by the request to correlate + this result set and the request + The ID of the group + The member to roles map + + + Represents the titles for a group + + + Get the ID as returned by the request to correlate + this result set and the request + + + Get the ID of the group + + + Get the titles + + + Construct a new instance of the GroupTitlesReplyEventArgs class + The ID as returned by the request to correlate + this result set and the request + The ID of the group + The titles + + + Represents the summary data for a group + + + Get the ID of the group + + + Get the summary data + + + Construct a new instance of the GroupAccountSummaryReplyEventArgs class + The ID of the group + The summary data + + + A response to a group create request + + + Get the ID of the group + + + true of the group was created successfully + + + A string containing the message + + + Construct a new instance of the GroupCreatedReplyEventArgs class + The ID of the group + the success or faulure of the request + A string containing additional information + + + Represents a response to a request + + + Get the ID of the group + + + true of the request was successful + + + Construct a new instance of the GroupOperationEventArgs class + The ID of the group + true of the request was successful + + + Represents your agent leaving a group + + + Get the ID of the group + + + Construct a new instance of the GroupDroppedEventArgs class + The ID of the group + + + Represents a list of active group notices + + + Get the ID of the group + + + Get the notices list + + + Construct a new instance of the GroupNoticesListReplyEventArgs class + The ID of the group + The list containing active notices + + + Represents the profile of a group + + + Get the group profile + + + Construct a new instance of the GroupProfileEventArgs class + The group profile + + + + Provides notification of a group invitation request sent by another Avatar + + The invitation is raised when another avatar makes an offer for our avatar + to join a group. + + + The ID of the Avatar sending the group invitation + + + The name of the Avatar sending the group invitation + + + A message containing the request information which includes + the name of the group, the groups charter and the fee to join details + + + The Simulator + + + Set to true to accept invitation, false to decline + + + + Result of the request for list of agents banned from a group + + + + Indicates if list of banned agents for a group was successfully retrieved + + + Indicates if list of banned agents for a group was successfully retrieved + + + Array containing a list of UUIDs of the agents banned from a group + + + + Static helper functions and global variables + + + + This header flag signals that ACKs are appended to the packet + + + This header flag signals that this packet has been sent before + + + This header flags signals that an ACK is expected for this packet + + + This header flag signals that the message is compressed using zerocoding + + + + Passed to Logger.Log() to identify the severity of a log entry + + + + No logging information will be output + + + Non-noisy useful information, may be helpful in + debugging a problem + + + A non-critical error occurred. A warning will not + prevent the rest of the library from operating as usual, + although it may be indicative of an underlying issue + + + A critical error has occurred. Generally this will + be followed by the network layer shutting down, although the + stability of the library after an error is uncertain + + + Used for internal testing, this logging level can + generate very noisy (long and/or repetitive) messages. Don't + pass this to the Log() function, use DebugLog() instead. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Given an X/Y location in absolute (grid-relative) terms, a region + handle is returned along with the local X/Y location in that region + + The absolute X location, a number such as + 255360.35 + The absolute Y location, a number such as + 255360.35 + The sim-local X position of the global X + position, a value from 0.0 to 256.0 + The sim-local Y position of the global Y + position, a value from 0.0 to 256.0 + A 64-bit region handle that can be used to teleport to + + + + Converts a floating point number to a terse string format used for + transmitting numbers in wearable asset files + + Floating point number to convert to a string + A terse string representation of the input number + + + + Convert a variable length field (byte array) to a string, with a + field name prepended to each line of the output + + If the byte array has unprintable characters in it, a + hex dump will be written instead + The StringBuilder object to write to + The byte array to convert to a string + A field name to prepend to each line of output + + + + Decode a zerocoded byte array, used to decompress packets marked + with the zerocoded flag + + Any time a zero is encountered, the next byte is a count + of how many zeroes to expand. One zero is encoded with 0x00 0x01, + two zeroes is 0x00 0x02, three zeroes is 0x00 0x03, etc. The + first four bytes are copied directly to the output buffer. + + The byte array to decode + The length of the byte array to decode. This + would be the length of the packet up to (but not including) any + appended ACKs + The output byte array to decode to + The length of the output buffer + + + + Encode a byte array with zerocoding. Used to compress packets marked + with the zerocoded flag. Any zeroes in the array are compressed down + to a single zero byte followed by a count of how many zeroes to expand + out. A single zero becomes 0x00 0x01, two zeroes becomes 0x00 0x02, + three zeroes becomes 0x00 0x03, etc. The first four bytes are copied + directly to the output buffer. + + The byte array to encode + The length of the byte array to encode + The output byte array to encode to + The length of the output buffer + + + + Calculates the CRC (cyclic redundancy check) needed to upload inventory. + + Creation date + Sale type + Inventory type + Type + Asset ID + Group ID + Sale price + Owner ID + Creator ID + Item ID + Folder ID + Everyone mask (permissions) + Flags + Next owner mask (permissions) + Group mask (permissions) + Owner mask (permissions) + The calculated CRC + + + + Attempts to load a file embedded in the assembly + + The filename of the resource to load + A Stream for the requested file, or null if the resource + was not successfully loaded + + + + Attempts to load a file either embedded in the assembly or found in + a given search path + + The filename of the resource to load + An optional path that will be searched if + the asset is not found embedded in the assembly + A Stream for the requested file, or null if the resource + was not successfully loaded + + + + Converts a list of primitives to an object that can be serialized + with the LLSD system + + Primitives to convert to a serializable object + An object that can be serialized with LLSD + + + + Deserializes OSD in to a list of primitives + + Structure holding the serialized primitive list, + must be of the SDMap type + A list of deserialized primitives + + + + Converts a struct or class object containing fields only into a key value separated string + + The struct object + A string containing the struct fields as the keys, and the field value as the value separated + + + // Add the following code to any struct or class containing only fields to override the ToString() + // method to display the values of the passed object + + /// Print the struct data as a string + ///A string containing the field name, and field value + public override string ToString() + { + return Helpers.StructToString(this); + } + + + + + + The InternalDictionary class is used through the library for storing key/value pairs. + It is intended to be a replacement for the generic Dictionary class and should + be used in its place. It contains several methods for allowing access to the data from + outside the library that are read only and thread safe. + + + Key + Value + + + Internal dictionary that this class wraps around. Do not + modify or enumerate the contents of this dictionary without locking + on this member + + + + Gets the number of Key/Value pairs contained in the + + + + + Initializes a new instance of the Class + with the specified key/value, has the default initial capacity. + + + + // initialize a new InternalDictionary named testDict with a string as the key and an int as the value. + public InternalDictionary<string, int> testDict = new InternalDictionary<string, int>(); + + + + + + Initializes a new instance of the Class + with the specified key/value, has its initial valies copied from the specified + + + + to copy initial values from + + + // initialize a new InternalDictionary named testAvName with a UUID as the key and an string as the value. + // populates with copied values from example KeyNameCache Dictionary. + + // create source dictionary + Dictionary<UUID, string> KeyNameCache = new Dictionary<UUID, string>(); + KeyNameCache.Add("8300f94a-7970-7810-cf2c-fc9aa6cdda24", "Jack Avatar"); + KeyNameCache.Add("27ba1e40-13f7-0708-3e98-5819d780bd62", "Jill Avatar"); + + // Initialize new dictionary. + public InternalDictionary<UUID, string> testAvName = new InternalDictionary<UUID, string>(KeyNameCache); + + + + + + Initializes a new instance of the Class + with the specified key/value, With its initial capacity specified. + + Initial size of dictionary + + + // initialize a new InternalDictionary named testDict with a string as the key and an int as the value, + // initially allocated room for 10 entries. + public InternalDictionary<string, int> testDict = new InternalDictionary<string, int>(10); + + + + + + Try to get entry from with specified key + + Key to use for lookup + Value returned + if specified key exists, if not found + + + // find your avatar using the Simulator.ObjectsAvatars InternalDictionary: + Avatar av; + if (Client.Network.CurrentSim.ObjectsAvatars.TryGetValue(Client.Self.AgentID, out av)) + Console.WriteLine("Found Avatar {0}", av.Name); + + + + + + + Finds the specified match. + + The match. + Matched value + + + // use a delegate to find a prim in the ObjectsPrimitives InternalDictionary + // with the ID 95683496 + uint findID = 95683496; + Primitive findPrim = sim.ObjectsPrimitives.Find( + delegate(Primitive prim) { return prim.ID == findID; }); + + + + + Find All items in an + return matching items. + a containing found items. + + Find All prims within 20 meters and store them in a List + + int radius = 20; + List<Primitive> prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll( + delegate(Primitive prim) { + Vector3 pos = prim.Position; + return ((prim.ParentID == 0) && (pos != Vector3.Zero) && (Vector3.Distance(pos, location) < radius)); + } + ); + + + + + Find All items in an + return matching keys. + a containing found keys. + + Find All keys which also exist in another dictionary + + List<UUID> matches = myDict.FindAll( + delegate(UUID id) { + return myOtherDict.ContainsKey(id); + } + ); + + + + + Perform an on each entry in an + to perform + + + // Iterates over the ObjectsPrimitives InternalDictionary and prints out some information. + Client.Network.CurrentSim.ObjectsPrimitives.ForEach( + delegate(Primitive prim) + { + if (prim.Text != null) + { + Console.WriteLine("NAME={0} ID = {1} TEXT = '{2}'", + prim.PropertiesFamily.Name, prim.ID, prim.Text); + } + }); + + + + + Perform an on each key of an + to perform + + + + Perform an on each KeyValuePair of an + + to perform + + + Check if Key exists in Dictionary + Key to check for + if found, otherwise + + + Check if Value exists in Dictionary + Value to check for + if found, otherwise + + + + Adds the specified key to the dictionary, dictionary locking is not performed, + + + The key + The value + + + + Removes the specified key, dictionary locking is not performed + + The key. + if successful, otherwise + + + + Indexer for the dictionary + + The key + The value + + + + Exception class to identify inventory exceptions + + + + + Responsible for maintaining inventory structure. Inventory constructs nodes + and manages node children as is necessary to maintain a coherant hirarchy. + Other classes should not manipulate or create InventoryNodes explicitly. When + A node's parent changes (when a folder is moved, for example) simply pass + Inventory the updated InventoryFolder and it will make the appropriate changes + to its internal representation. + + + + The event subscribers, null of no subscribers + + + Raises the InventoryObjectUpdated Event + A InventoryObjectUpdatedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the InventoryObjectRemoved Event + A InventoryObjectRemovedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the InventoryObjectAdded Event + A InventoryObjectAddedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + + The root folder of this avatars inventory + + + + + The default shared library folder + + + + + The root node of the avatars inventory + + + + + The root node of the default shared library + + + + + Returns the contents of the specified folder + + A folder's UUID + The contents of the folder corresponding to folder + When folder does not exist in the inventory + + + + Updates the state of the InventoryNode and inventory data structure that + is responsible for the InventoryObject. If the item was previously not added to inventory, + it adds the item, and updates structure accordingly. If it was, it updates the + InventoryNode, changing the parent node if item.parentUUID does + not match node.Parent.Data.UUID. + + You can not set the inventory root folder using this method + + The InventoryObject to store + + + + Removes the InventoryObject and all related node data from Inventory. + + The InventoryObject to remove. + + + + Used to find out if Inventory contains the InventoryObject + specified by uuid. + + The UUID to check. + true if inventory contains uuid, false otherwise + + + + Saves the current inventory structure to a cache file + + Name of the cache file to save to + + + + Loads in inventory cache file into the inventory structure. Note only valid to call after login has been successful. + + Name of the cache file to load + The number of inventory items sucessfully reconstructed into the inventory node tree + + + + By using the bracket operator on this class, the program can get the + InventoryObject designated by the specified uuid. If the value for the corresponding + UUID is null, the call is equivelant to a call to RemoveNodeFor(this[uuid]). + If the value is non-null, it is equivelant to a call to UpdateNodeFor(value), + the uuid parameter is ignored. + + The UUID of the InventoryObject to get or set, ignored if set to non-null value. + The InventoryObject corresponding to uuid. + + + Sort by name + + + Sort by date + + + Sort folders by name, regardless of whether items are + sorted by name or date + + + Place system folders at the top + + + + Possible destinations for DeRezObject request + + + + + + + Copy from in-world to agent inventory + + + Derez to TaskInventory + + + + + + Take Object + + + + + + Delete Object + + + Put an avatar attachment into agent inventory + + + + + + Return an object back to the owner's inventory + + + Return a deeded object back to the last owner's inventory + + + + Upper half of the Flags field for inventory items + + + + Indicates that the NextOwner permission will be set to the + most restrictive set of permissions found in the object set + (including linkset items and object inventory items) on next rez + + + Indicates that the object sale information has been + changed + + + If set, and a slam bit is set, indicates BaseMask will be overwritten on Rez + + + If set, and a slam bit is set, indicates OwnerMask will be overwritten on Rez + + + If set, and a slam bit is set, indicates GroupMask will be overwritten on Rez + + + If set, and a slam bit is set, indicates EveryoneMask will be overwritten on Rez + + + If set, and a slam bit is set, indicates NextOwnerMask will be overwritten on Rez + + + Indicates whether this object is composed of multiple + items or not + + + Indicates that the asset is only referenced by this + inventory item. If this item is deleted or updated to reference a + new assetID, the asset can be deleted + + + + Base Class for Inventory Items + + + + of item/folder + + + of parent folder + + + Name of item/folder + + + Item/Folder Owners + + + + Constructor, takes an itemID as a parameter + + The of the item + + + + + + + + + + + + + + + + Generates a number corresponding to the value of the object to support the use of a hash table, + suitable for use in hashing algorithms and data structures such as a hash table + + A Hashcode of all the combined InventoryBase fields + + + + Determine whether the specified object is equal to the current object + + InventoryBase object to compare against + true if objects are the same + + + + Determine whether the specified object is equal to the current object + + InventoryBase object to compare against + true if objects are the same + + + + Convert inventory to OSD + + OSD representation + + + + An Item in Inventory + + + + The of this item + + + The combined of this item + + + The type of item from + + + The type of item from the enum + + + The of the creator of this item + + + A Description of this item + + + The s this item is set to or owned by + + + If true, item is owned by a group + + + The price this item can be purchased for + + + The type of sale from the enum + + + Combined flags from + + + Time and date this inventory item was created, stored as + UTC (Coordinated Universal Time) + + + Used to update the AssetID in requests sent to the server + + + The of the previous owner of the item + + + + Construct a new InventoryItem object + + The of the item + + + + Construct a new InventoryItem object of a specific Type + + The type of item from + of the item + + + + Indicates inventory item is a link + + True if inventory item is a link to another inventory item + + + + + + + + + + + + + + + + Generates a number corresponding to the value of the object to support the use of a hash table. + Suitable for use in hashing algorithms and data structures such as a hash table + + A Hashcode of all the combined InventoryItem fields + + + + Compares an object + + The object to compare + true if comparison object matches + + + + Determine whether the specified object is equal to the current object + + The object to compare against + true if objects are the same + + + + Determine whether the specified object is equal to the current object + + The object to compare against + true if objects are the same + + + + Create InventoryItem from OSD + + OSD Data that makes up InventoryItem + Inventory item created + + + + Convert InventoryItem to OSD + + OSD representation of InventoryItem + + + + InventoryTexture Class representing a graphical image + + + + + + Construct an InventoryTexture object + + A which becomes the + objects AssetUUID + + + + Construct an InventoryTexture object from a serialization stream + + + + + InventorySound Class representing a playable sound + + + + + Construct an InventorySound object + + A which becomes the + objects AssetUUID + + + + Construct an InventorySound object from a serialization stream + + + + + InventoryCallingCard Class, contains information on another avatar + + + + + Construct an InventoryCallingCard object + + A which becomes the + objects AssetUUID + + + + Construct an InventoryCallingCard object from a serialization stream + + + + + InventoryLandmark Class, contains details on a specific location + + + + + Construct an InventoryLandmark object + + A which becomes the + objects AssetUUID + + + + Construct an InventoryLandmark object from a serialization stream + + + + + Landmarks use the InventoryItemFlags struct and will have a flag of 1 set if they have been visited + + + + + InventoryObject Class contains details on a primitive or coalesced set of primitives + + + + + Construct an InventoryObject object + + A which becomes the + objects AssetUUID + + + + Construct an InventoryObject object from a serialization stream + + + + + Gets or sets the upper byte of the Flags value + + + + + Gets or sets the object attachment point, the lower byte of the Flags value + + + + + InventoryNotecard Class, contains details on an encoded text document + + + + + Construct an InventoryNotecard object + + A which becomes the + objects AssetUUID + + + + Construct an InventoryNotecard object from a serialization stream + + + + + InventoryCategory Class + + TODO: Is this even used for anything? + + + + Construct an InventoryCategory object + + A which becomes the + objects AssetUUID + + + + Construct an InventoryCategory object from a serialization stream + + + + + InventoryLSL Class, represents a Linden Scripting Language object + + + + + Construct an InventoryLSL object + + A which becomes the + objects AssetUUID + + + + Construct an InventoryLSL object from a serialization stream + + + + + InventorySnapshot Class, an image taken with the viewer + + + + + Construct an InventorySnapshot object + + A which becomes the + objects AssetUUID + + + + Construct an InventorySnapshot object from a serialization stream + + + + + InventoryAttachment Class, contains details on an attachable object + + + + + Construct an InventoryAttachment object + + A which becomes the + objects AssetUUID + + + + Construct an InventoryAttachment object from a serialization stream + + + + + Get the last AttachmentPoint this object was attached to + + + + + InventoryWearable Class, details on a clothing item or body part + + + + + Construct an InventoryWearable object + + A which becomes the + objects AssetUUID + + + + Construct an InventoryWearable object from a serialization stream + + + + + The , Skin, Shape, Skirt, Etc + + + + + InventoryAnimation Class, A bvh encoded object which animates an avatar + + + + + Construct an InventoryAnimation object + + A which becomes the + objects AssetUUID + + + + Construct an InventoryAnimation object from a serialization stream + + + + + InventoryGesture Class, details on a series of animations, sounds, and actions + + + + + Construct an InventoryGesture object + + A which becomes the + objects AssetUUID + + + + Construct an InventoryGesture object from a serialization stream + + + + + A folder contains s and has certain attributes specific + to itself + + + + The Preferred for a folder. + + + The Version of this folder + + + Number of child items this folder contains. + + + + Constructor + + UUID of the folder + + + + + + + + + + Get Serilization data for this InventoryFolder object + + + + + Construct an InventoryFolder object from a serialization stream + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create InventoryFolder from OSD + + OSD Data that makes up InventoryFolder + Inventory folder created + + + + Convert InventoryItem to OSD + + OSD representation of InventoryItem + + + + Tools for dealing with agents inventory + + + + Used for converting shadow_id to asset_id + + + + Callback for inventory item creation finishing + + Whether the request to create an inventory + item succeeded or not + Inventory item being created. If success is + false this will be null + + + + Callback for an inventory item being create from an uploaded asset + + true if inventory item creation was successful + + + + + + + + + + + + The event subscribers, null of no subscribers + + + Raises the ItemReceived Event + A ItemReceivedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the FolderUpdated Event + A FolderUpdatedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the InventoryObjectOffered Event + A InventoryObjectOfferedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + an inventory object sent by another avatar or primitive + + + The event subscribers, null of no subscribers + + + Raises the TaskItemReceived Event + A TaskItemReceivedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the FindObjectByPath Event + A FindObjectByPathEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the TaskInventoryReply Event + A TaskInventoryReplyEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + + Reply received when uploading an inventory asset + + Has upload been successful + Error message if upload failed + Inventory asset UUID + New asset UUID + + + The event subscribers, null of no subscribers + + + Raises the SaveAssetToInventory Event + A SaveAssetToInventoryEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + + Delegate that is invoked when script upload is completed + + Has upload succeded (note, there still might be compile errors) + Upload status message + Is compilation successful + If compilation failed, list of error messages, null on compilation success + Script inventory UUID + Script's new asset UUID + + + The event subscribers, null of no subscribers + + + Raises the ScriptRunningReply Event + A ScriptRunningReplyEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + Partial mapping of FolderTypes to folder names + + + + Get this agents Inventory data + + + + + Default constructor + + Reference to the GridClient object + + + + Fetch an inventory item from the dataserver + + The items + The item Owners + a integer representing the number of milliseconds to wait for results + An object on success, or null if no item was found + Items will also be sent to the event + + + + Request A single inventory item + + The items + The item Owners + + + + + Request inventory items + + Inventory items to request + Owners of the inventory items + + + + + Request inventory items via Capabilities + + Inventory items to request + Owners of the inventory items + + + + + Get contents of a folder + + The of the folder to search + The of the folders owner + true to retrieve folders + true to retrieve items + sort order to return results in + a integer representing the number of milliseconds to wait for results + A list of inventory items matching search criteria within folder + + InventoryFolder.DescendentCount will only be accurate if both folders and items are + requested + + + + Request the contents of an inventory folder + + The folder to search + The folder owners + true to return s contained in folder + true to return s containd in folder + the sort order to return items in + + + + + Request the contents of an inventory folder using HTTP capabilities + + The folder to search + The folder owners + true to return s contained in folder + true to return s containd in folder + the sort order to return items in + + + + + Returns the UUID of the folder (category) that defaults to + containing 'type'. The folder is not necessarily only for that + type + + This will return the root folder if one does not exist + + The UUID of the desired folder if found, the UUID of the RootFolder + if not found, or UUID.Zero on failure + + + + Find an object in inventory using a specific path to search + + The folder to begin the search in + The object owners + A string path to search + milliseconds to wait for a reply + Found items or if + timeout occurs or item is not found + + + + Find inventory items by path + + The folder to begin the search in + The object owners + A string path to search, folders/objects separated by a '/' + Results are sent to the event + + + + Search inventory Store object for an item or folder + + The folder to begin the search in + An array which creates a path to search + Number of levels below baseFolder to conduct searches + if True, will stop searching after first match is found + A list of inventory items found + + + + Move an inventory item or folder to a new location + + The item or folder to move + The to move item or folder to + + + + Move an inventory item or folder to a new location and change its name + + The item or folder to move + The to move item or folder to + The name to change the item or folder to + + + + Move and rename a folder + + The source folders + The destination folders + The name to change the folder to + + + + Update folder properties + + of the folder to update + Sets folder's parent to + Folder name + Folder type + + + + Move a folder + + The source folders + The destination folders + + + + Move multiple folders, the keys in the Dictionary parameter, + to a new parents, the value of that folder's key. + + A Dictionary containing the + of the source as the key, and the + of the destination as the value + + + + Move an inventory item to a new folder + + The of the source item to move + The of the destination folder + + + + Move and rename an inventory item + + The of the source item to move + The of the destination folder + The name to change the folder to + + + + Move multiple inventory items to new locations + + A Dictionary containing the + of the source item as the key, and the + of the destination folder as the value + + + + Remove descendants of a folder + + The of the folder + + + + Remove a single item from inventory + + The of the inventory item to remove + + + + Remove a folder from inventory + + The of the folder to remove + + + + Remove multiple items or folders from inventory + + A List containing the s of items to remove + A List containing the s of the folders to remove + + + + Empty the Lost and Found folder + + + + + Empty the Trash folder + + + + + + + + + + + Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. + + + + + + + + + + + + + Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. + + + + + + + + Creates a new inventory folder + + ID of the folder to put this folder in + Name of the folder to create + The UUID of the newly created folder + + + + Creates a new inventory folder + + ID of the folder to put this folder in + Name of the folder to create + Sets this folder as the default folder + for new assets of the specified type. Use FolderType.None + to create a normal folder, otherwise it will likely create a + duplicate of an existing folder type + The UUID of the newly created folder + If you specify a preferred type of AsseType.Folder + it will create a new root folder which may likely cause all sorts + of strange problems + + + + Create an inventory item and upload asset data + + Asset data + Inventory item name + Inventory item description + Asset type + Inventory type + Put newly created inventory in this folder + Delegate that will receive feedback on success or failure + + + + Create an inventory item and upload asset data + + Asset data + Inventory item name + Inventory item description + Asset type + Inventory type + Put newly created inventory in this folder + Permission of the newly created item + (EveryoneMask, GroupMask, and NextOwnerMask of Permissions struct are supported) + Delegate that will receive feedback on success or failure + + + + Creates inventory link to another inventory item or folder + + Put newly created link in folder with this UUID + Inventory item or folder + Method to call upon creation of the link + + + + Creates inventory link to another inventory item + + Put newly created link in folder with this UUID + Original inventory item + Method to call upon creation of the link + + + + Creates inventory link to another inventory folder + + Put newly created link in folder with this UUID + Original inventory folder + Method to call upon creation of the link + + + + Creates inventory link to another inventory item or folder + + Put newly created link in folder with this UUID + Original item's UUID + Name + Description + Asset Type + Inventory Type + Transaction UUID + Method to call upon creation of the link + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Request a copy of an asset embedded within a notecard + + Usually UUID.Zero for copying an asset from a notecard + UUID of the notecard to request an asset from + Target folder for asset to go to in your inventory + UUID of the embedded asset + callback to run when item is copied to inventory + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Save changes to notecard embedded in object contents + + Encoded notecard asset data + Notecard UUID + Object's UUID + Called upon finish of the upload with status information + + + + Upload new gesture asset for an inventory gesture item + + Encoded gesture asset + Gesture inventory UUID + Callback whick will be called when upload is complete + + + + Update an existing script in an agents Inventory + + A byte[] array containing the encoded scripts contents + the itemID of the script + if true, sets the script content to run on the mono interpreter + + + + + Update an existing script in an task Inventory + + A byte[] array containing the encoded scripts contents + the itemID of the script + UUID of the prim containting the script + if true, sets the script content to run on the mono interpreter + if true, sets the script to running + + + + + Rez an object from inventory + + Simulator to place object in + Rotation of the object when rezzed + Vector of where to place object + InventoryItem object containing item details + + + + Rez an object from inventory + + Simulator to place object in + Rotation of the object when rezzed + Vector of where to place object + InventoryItem object containing item details + UUID of group to own the object + + + + Rez an object from inventory + + Simulator to place object in + Rotation of the object when rezzed + Vector of where to place object + InventoryItem object containing item details + UUID of group to own the object + User defined queryID to correlate replies + If set to true, the CreateSelected flag + will be set on the rezzed object + + + + Rez an object from inventory + + Simulator to place object in + TaskID object when rezzed + Rotation of the object when rezzed + Vector of where to place object + InventoryItem object containing item details + UUID of group to own the object + User defined queryID to correlate replies + If set to true, the CreateSelected flag + will be set on the rezzed object + + + + DeRez an object from the simulator to the agents Objects folder in the agents Inventory + + The simulator Local ID of the object + If objectLocalID is a child primitive in a linkset, the entire linkset will be derezzed + + + + DeRez an object from the simulator and return to inventory + + The simulator Local ID of the object + The type of destination from the enum + The destination inventory folders -or- + if DeRezzing object to a tasks Inventory, the Tasks + The transaction ID for this request which + can be used to correlate this request with other packets + If objectLocalID is a child primitive in a linkset, the entire linkset will be derezzed + + + + Rez an item from inventory to its previous simulator location + + + + + + + + + Give an inventory item to another avatar + + The of the item to give + The name of the item + The type of the item from the enum + The of the recipient + true to generate a beameffect during transfer + + + + Give an inventory Folder with contents to another avatar + + The of the Folder to give + The name of the folder + The type of the item from the enum + The of the recipient + true to generate a beameffect during transfer + + + + Copy or move an from agent inventory to a task (primitive) inventory + + The target object + The item to copy or move from inventory + + For items with copy permissions a copy of the item is placed in the tasks inventory, + for no-copy items the object is moved to the tasks inventory + + + + Retrieve a listing of the items contained in a task (Primitive) + + The tasks + The tasks simulator local ID + milliseconds to wait for reply from simulator + A list containing the inventory items inside the task or null + if a timeout occurs + This request blocks until the response from the simulator arrives + or timeoutMS is exceeded + + + + Request the contents of a tasks (primitives) inventory from the + current simulator + + The LocalID of the object + + + + + Request the contents of a tasks (primitives) inventory + + The simulator Local ID of the object + A reference to the simulator object that contains the object + + + + + Move an item from a tasks (Primitive) inventory to the specified folder in the avatars inventory + + LocalID of the object in the simulator + UUID of the task item to move + The ID of the destination folder in this agents inventory + Simulator Object + Raises the event + + + + Remove an item from an objects (Prim) Inventory + + LocalID of the object in the simulator + UUID of the task item to remove + Simulator Object + You can confirm the removal by comparing the tasks inventory serial before and after the + request with the request combined with + the event + + + + Copy an InventoryScript item from the Agents Inventory into a primitives task inventory + + An unsigned integer representing a primitive being simulated + An which represents a script object from the agents inventory + true to set the scripts running state to enabled + A Unique Transaction ID + + The following example shows the basic steps necessary to copy a script from the agents inventory into a tasks inventory + and assumes the script exists in the agents inventory. + + uint primID = 95899503; // Fake prim ID + UUID scriptID = UUID.Parse("92a7fe8a-e949-dd39-a8d8-1681d8673232"); // Fake Script UUID in Inventory + + Client.Inventory.FolderContents(Client.Inventory.FindFolderForType(AssetType.LSLText), Client.Self.AgentID, + false, true, InventorySortOrder.ByName, 10000); + + Client.Inventory.RezScript(primID, (InventoryItem)Client.Inventory.Store[scriptID]); + + + + + + Request the running status of a script contained in a task (primitive) inventory + + The ID of the primitive containing the script + The ID of the script + The event can be used to obtain the results of the + request + + + + + Send a request to set the running state of a script contained in a task (primitive) inventory + + The ID of the primitive containing the script + The ID of the script + true to set the script running, false to stop a running script + To verify the change you can use the method combined + with the event + + + + Create a CRC from an InventoryItem + + The source InventoryItem + A uint representing the source InventoryItem as a CRC + + + + Reverses a cheesy XORing with a fixed UUID to convert a shadow_id to an asset_id + + Obfuscated shadow_id value + Deobfuscated asset_id value + + + + Does a cheesy XORing with a fixed UUID to convert an asset_id to a shadow_id + + asset_id value to obfuscate + Obfuscated shadow_id value + + + + Wrapper for creating a new object + + The type of item from the enum + The of the newly created object + An object with the type and id passed + + + + Parse the results of a RequestTaskInventory() response + + A string which contains the data from the task reply + A List containing the items contained within the tasks inventory + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + + UpdateCreateInventoryItem packets are received when a new inventory item + is created. This may occur when an object that's rezzed in world is + taken into inventory, when an item is created using the CreateInventoryItem + packet, or when an object is purchased + + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Set to true to accept offer, false to decline it + + + The folder to accept the inventory into, if null default folder for will be used + + + + Callback when an inventory object is accepted and received from a + task inventory. This is the callback in which you actually get + the ItemID, as in ObjectOfferedCallback it is null when received + from a task. + + + + + + + User data + + + + + + + + + + + + + For inventory folder nodes specifies weather the folder needs to be + refreshed from the server + + + + + + + + + + + + + + + + De-serialization constructor for the InventoryNode Class + + + + + Serialization handler for the InventoryNode Class + + + + + De-serialization handler for the InventoryNode Class + + + + + + + + + + + Singleton logging class for the entire library + + + + + Callback used for client apps to receive log messages from + the library + + Data being logged + The severity of the log entry from + + + Triggered whenever a message is logged. If this is left + null, log messages will go to the console + + + log4net logging engine + + + + Default constructor + + + + + Send a log message to the logging engine + + The log message + The severity of the log entry + + + + Send a log message to the logging engine + + The log message + The severity of the log entry + Instance of the client + + + + Send a log message to the logging engine + + The log message + The severity of the log entry + Exception that was raised + + + + Send a log message to the logging engine + + The log message + The severity of the log entry + Instance of the client + Exception that was raised + + + + If the library is compiled with DEBUG defined, an event will be + fired if an OnLogMessage handler is registered and the + message will be sent to the logging engine + + The message to log at the DEBUG level to the + current logging engine + + + + If the library is compiled with DEBUG defined and + GridClient.Settings.DEBUG is true, an event will be + fired if an OnLogMessage handler is registered and the + message will be sent to the logging engine + + The message to log at the DEBUG level to the + current logging engine + Instance of the client + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Status of the last application run. + Used for error reporting to the grid login service for statistical purposes. + + + + Application exited normally + + + Application froze + + + Application detected error and exited abnormally + + + Other crash + + + Application froze during logout + + + Application crashed during logout + + + + Login Request Parameters + + + + The URL of the Login Server + + + The number of milliseconds to wait before a login is considered + failed due to timeout + + + The request method + login_to_simulator is currently the only supported method + + + The Agents First name + + + The Agents Last name + + + A md5 hashed password + plaintext password will be automatically hashed + + + The agents starting location once logged in + Either "last", "home", or a string encoded URI + containing the simulator name and x/y/z coordinates e.g: uri:hooper&128&152&17 + + + A string containing the client software channel information + Second Life Release + + + The client software version information + The official viewer uses: Second Life Release n.n.n.n + where n is replaced with the current version of the viewer + + + A string containing the platform information the agent is running on + + + A string containing version number for OS the agent is running on + + + A string hash of the network cards Mac Address + + + Unknown or deprecated + + + A string hash of the first disk drives ID used to identify this clients uniqueness + + + A string containing the viewers Software, this is not directly sent to the login server but + instead is used to generate the Version string + + + A string representing the software creator. This is not directly sent to the login server but + is used by the library to generate the Version information + + + If true, this agent agrees to the Terms of Service of the grid its connecting to + + + Unknown + + + Status of the last application run sent to the grid login server for statistical purposes + + + An array of string sent to the login server to enable various options + + + A randomly generated ID to distinguish between login attempts. This value is only used + internally in the library and is never sent over the wire + + + + Default constuctor, initializes sane default values + + + + + Instantiates new LoginParams object and fills in the values + + Instance of GridClient to read settings from + Login first name + Login last name + Password + Login channnel (application name) + Client version, should be application name + version number + + + + Instantiates new LoginParams object and fills in the values + + Instance of GridClient to read settings from + Login first name + Login last name + Password + Login channnel (application name) + Client version, should be application name + version number + URI of the login server + + + + The decoded data returned from the login server after a successful login + + + + true, false, indeterminate + + + Login message of the day + + + M or PG, also agent_region_access and agent_access_max + + + + Parse LLSD Login Reply Data + + An + contaning the login response data + XML-RPC logins do not require this as XML-RPC.NET + automatically populates the struct properly using attributes + + + + Login Routines + + + NetworkManager is responsible for managing the network layer of + OpenMetaverse. It tracks all the server connections, serializes + outgoing traffic and deserializes incoming traffic, and provides + instances of delegates for network-related events. + + + + The event subscribers, null of no subscribers + + + Raises the LoginProgress Event + A LoginProgressEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + + + + + + + + + + + Called when a reply is received from the login server, the + login sequence will block until this event returns + + + Seed CAPS URL returned from the login server + + + Current state of logging in + + + Upon login failure, contains a short string key for the + type of login error that occurred + + + The raw XML-RPC reply from the login server, exactly as it + was received (minus the HTTP header) + + + During login this contains a descriptive version of + LoginStatusCode. After a successful login this will contain the + message of the day, and after a failed login a descriptive error + message will be returned + + + Maximum number of groups an agent can belong to, -1 for unlimited + + + Server side baking service URL + + + Parsed login response data + + + A list of packets obtained during the login process which + networkmanager will log but not process + + + + Generate sane default values for a login request + + Account first name + Account last name + Account password + Client application name (channel) + Client application name + version + A populated struct containing + sane defaults + + + + Simplified login that takes the most common and required fields + + Account first name + Account last name + Account password + Client application name (channel) + Client application name + version + Whether the login was successful or not. On failure the + LoginErrorKey string will contain the error code and LoginMessage + will contain a description of the error + + + + Simplified login that takes the most common fields along with a + starting location URI, and can accept an MD5 string instead of a + plaintext password + + Account first name + Account last name + Account password or MD5 hash of the password + such as $1$1682a1e45e9f957dcdf0bb56eb43319c + Client application name (channel) + Starting location URI that can be built with + StartLocation() + Client application name + version + Whether the login was successful or not. On failure the + LoginErrorKey string will contain the error code and LoginMessage + will contain a description of the error + + + + Login that takes a struct of all the values that will be passed to + the login server + + The values that will be passed to the login + server, all fields must be set even if they are String.Empty + Whether the login was successful or not. On failure the + LoginErrorKey string will contain the error code and LoginMessage + will contain a description of the error + + + + Build a start location URI for passing to the Login function + + Name of the simulator to start in + X coordinate to start at + Y coordinate to start at + Z coordinate to start at + String with a URI that can be used to login to a specified + location + + + + LoginParams and the initial login XmlRpcRequest were made on a remote machine. + This method now initializes libomv with the results. + + + + + Handles response from XML-RPC login replies + + + + + Handles response from XML-RPC login replies with already parsed LoginResponseData + + + + + Handle response from LLSD login replies + + + + + + + + Get current OS + + Either "Win" or "Linux" + + + + Gets the current OS version number + + The platform version. + + + + Get clients default Mac Address + + A string containing the first found Mac Address + + + + Explains why a simulator or the grid disconnected from us + + + + The client requested the logout or simulator disconnect + + + The server notified us that it is disconnecting + + + Either a socket was closed or network traffic timed out + + + The last active simulator shut down + + + + Holds a simulator reference and a decoded packet, these structs are put in + the packet inbox for event handling + + + + Reference to the simulator that this packet came from + + + Packet that needs to be processed + + + + Holds a simulator reference and a serialized packet, these structs are put in + the packet outbox for sending + + + + Reference to the simulator this packet is destined for + + + Packet that needs to be sent + + + Sequence number of the wrapped packet + + + Number of times this packet has been resent + + + Environment.TickCount when this packet was last sent over the wire + + + Type of the packet + + + The event subscribers, null of no subscribers + + + Raises the PacketSent Event + A PacketSentEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the LoggedOut Event + A LoggedOutEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the SimConnecting Event + A SimConnectingEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the SimConnected Event + A SimConnectedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the SimDisconnected Event + A SimDisconnectedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the Disconnected Event + A DisconnectedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the SimChanged Event + A SimChangedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the EventQueueRunning Event + A EventQueueRunningEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + Unique identifier associated with our connections to + simulators + + + The simulator that the logged in avatar is currently + occupying + + + Shows whether the network layer is logged in to the + grid or not + + + Number of packets in the incoming queue + + + Number of packets in the outgoing queue + + + All of the simulators we are currently connected to + + + Handlers for incoming capability events + + + Handlers for incoming packets + + + Incoming packets that are awaiting handling + + + Outgoing packets that are awaiting handling + + + + Default constructor + + Reference to the GridClient object + + + + Register an event handler for a packet. This is a low level event + interface and should only be used if you are doing something not + supported in the library + + Packet type to trigger events for + Callback to fire when a packet of this type + is received + + + + Register an event handler for a packet. This is a low level event + interface and should only be used if you are doing something not + supported in the library + + Packet type to trigger events for + Callback to fire when a packet of this type + is received + True if the callback should be ran + asynchronously. Only set this to false (synchronous for callbacks + that will always complete quickly) + If any callback for a packet type is marked as + asynchronous, all callbacks for that packet type will be fired + asynchronously + + + + Unregister an event handler for a packet. This is a low level event + interface and should only be used if you are doing something not + supported in the library + + Packet type this callback is registered with + Callback to stop firing events for + + + + Register a CAPS event handler. This is a low level event interface + and should only be used if you are doing something not supported in + the library + + Name of the CAPS event to register a handler for + Callback to fire when a CAPS event is received + + + + Unregister a CAPS event handler. This is a low level event interface + and should only be used if you are doing something not supported in + the library + + Name of the CAPS event this callback is + registered with + Callback to stop firing events for + + + + Send a packet to the simulator the avatar is currently occupying + + Packet to send + + + + Send a packet to a specified simulator + + Packet to send + Simulator to send the packet to + + + + Connect to a simulator + + IP address to connect to + Port to connect to + Handle for this simulator, to identify its + location in the grid + Whether to set CurrentSim to this new + connection, use this if the avatar is moving in to this simulator + URL of the capabilities server to use for + this sim connection + A Simulator object on success, otherwise null + + + + Connect to a simulator + + IP address and port to connect to + Handle for this simulator, to identify its + location in the grid + Whether to set CurrentSim to this new + connection, use this if the avatar is moving in to this simulator + URL of the capabilities server to use for + this sim connection + A Simulator object on success, otherwise null + + + + Begins the non-blocking logout. Makes sure that the LoggedOut event is + called even if the server does not send a logout reply, and Shutdown() + is properly called. + + + + + Initiate a blocking logout request. This will return when the logout + handshake has completed or when Settings.LOGOUT_TIMEOUT + has expired and the network layer is manually shut down + + + + + Initiate the logout process. The Shutdown() function + needs to be manually called. + + + + + Close a connection to the given simulator + + + + + + + Shutdown will disconnect all the sims except for the current sim + first, and then kill the connection to CurrentSim. This should only + be called if the logout process times out on RequestLogout + + Type of shutdown + + + + Shutdown will disconnect all the sims except for the current sim + first, and then kill the connection to CurrentSim. This should only + be called if the logout process times out on RequestLogout + + Type of shutdown + Shutdown message + + + + Searches through the list of currently connected simulators to find + one attached to the given IPEndPoint + + IPEndPoint of the Simulator to search for + A Simulator reference on success, otherwise null + + + + Fire an event when an event queue connects for capabilities + + Simulator the event queue is attached to + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + + A Name Value pair with additional settings, used in the protocol + primarily to transmit avatar names and active group in object packets + + + + Type of the value + + + Unknown + + + String value + + + + + + + + + + + + + + + Deprecated + + + String value, but designated as an asset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Constructor that takes all the fields as parameters + + + + + + + + + + Constructor that takes a single line from a NameValue field + + + + + + + + + + No report + + + Unknown report type + + + Bug report + + + Complaint report + + + Customer service report + + + + Bitflag field for ObjectUpdateCompressed data blocks, describing + which options are present for each object + + + + Unknown + + + Whether the object has a TreeSpecies + + + Whether the object has floating text ala llSetText + + + Whether the object has an active particle system + + + Whether the object has sound attached to it + + + Whether the object is attached to a root object or not + + + Whether the object has texture animation settings + + + Whether the object has an angular velocity + + + Whether the object has a name value pairs string + + + Whether the object has a Media URL set + + + + Specific Flags for MultipleObjectUpdate requests + + + + None + + + Change position of prims + + + Change rotation of prims + + + Change size of prims + + + Perform operation on link set + + + Scale prims uniformly, same as selecing ctrl+shift in the + viewer. Used in conjunction with Scale + + + + Special values in PayPriceReply. If the price is not one of these + literal value of the price should be use + + + + + Indicates that this pay option should be hidden + + + + + Indicates that this pay option should have the default value + + + + + Contains the variables sent in an object update packet for objects. + Used to track position and movement of prims and avatars + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Handles all network traffic related to prims and avatar positions and + movement. + + + + The event subscribers, null of no subscribers + + + Thread sync lock object + + + Raised when the simulator sends us data containing + A , Foliage or Attachment + + + + + The event subscribers, null of no subscribers + + + Raises the ObjectProperties Event + A ObjectPropertiesEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + additional information + + + + + The event subscribers, null of no subscribers + + + Raises the ObjectPropertiesUpdated Event + A ObjectPropertiesUpdatedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + Primitive.ObjectProperties for an object we are currently tracking + + + The event subscribers, null of no subscribers + + + Raises the ObjectPropertiesFamily Event + A ObjectPropertiesFamilyEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + additional and details + + + + The event subscribers, null of no subscribers + + + Raises the AvatarUpdate Event + A AvatarUpdateEventArgs object containing + the data sent from the simulator + + + + Raises the ParticleUpdate Event + + A ParticleUpdateEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + updated information for an + + + The event subscribers, null of no subscribers + + + Thread sync lock object + + + Raised when the simulator sends us data containing + and movement changes + + + The event subscribers, null of no subscribers + + + Raises the ObjectDataBlockUpdate Event + A ObjectDataBlockUpdateEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + updates to an Objects DataBlock + + + The event subscribers, null of no subscribers + + + Raises the KillObject Event + A KillObjectEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator informs us an + or is no longer within view + + + The event subscribers, null of no subscribers + + + Raises the KillObjects Event + A KillObjectsEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator informs us when a group of + or is no longer within view + + + The event subscribers, null of no subscribers + + + Raises the AvatarSitChanged Event + A AvatarSitChangedEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + updated sit information for our + + + The event subscribers, null of no subscribers + + + Raises the PayPriceReply Event + A PayPriceReplyEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + purchase price information for a + + + + Callback for getting object media data via CAP + + Indicates if the operation was succesfull + Object media version string + Array indexed on prim face of media entry data + + + The event subscribers, null of no subscribers + + + Raises the PhysicsProperties Event + A PhysicsPropertiesEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + additional information + + + + + Reference to the GridClient object + + + Does periodic dead reckoning calculation to convert + velocity and acceleration to new positions for objects + + + + Construct a new instance of the ObjectManager class + + A reference to the instance + + + + Request information for a single object from a + you are currently connected to + + The the object is located + The Local ID of the object + + + + Request information for multiple objects contained in + the same simulator + + The the objects are located + An array containing the Local IDs of the objects + + + + Attempt to purchase an original object, a copy, or the contents of + an object + + The the object is located + The Local ID of the object + Whether the original, a copy, or the object + contents are on sale. This is used for verification, if the this + sale type is not valid for the object the purchase will fail + Price of the object. This is used for + verification, if it does not match the actual price the purchase + will fail + Group ID that will be associated with the new + purchase + Inventory folder UUID where the object or objects + purchased should be placed + + + BuyObject(Client.Network.CurrentSim, 500, SaleType.Copy, + 100, UUID.Zero, Client.Self.InventoryRootFolderUUID); + + + + + + Request prices that should be displayed in pay dialog. This will triggger the simulator + to send us back a PayPriceReply which can be handled by OnPayPriceReply event + + The the object is located + The ID of the object + The result is raised in the event + + + + Select a single object. This will cause the to send us + an which will raise the event + + The the object is located + The Local ID of the object + + + + + Select a single object. This will cause the to send us + an which will raise the event + + The the object is located + The Local ID of the object + if true, a call to is + made immediately following the request + + + + + Select multiple objects. This will cause the to send us + an which will raise the event + + The the objects are located + An array containing the Local IDs of the objects + Should objects be deselected immediately after selection + + + + + Select multiple objects. This will cause the to send us + an which will raise the event + + The the objects are located + An array containing the Local IDs of the objects + + + + + Update the properties of an object + + The the object is located + The Local ID of the object + true to turn the objects physical property on + true to turn the objects temporary property on + true to turn the objects phantom property on + true to turn the objects cast shadows property on + + + + Update the properties of an object + + The the object is located + The Local ID of the object + true to turn the objects physical property on + true to turn the objects temporary property on + true to turn the objects phantom property on + true to turn the objects cast shadows property on + Type of the represetnation prim will have in the physics engine + Density - normal value 1000 + Friction - normal value 0.6 + Restitution - standard value 0.5 + Gravity multiplier - standar value 1.0 + + + + Sets the sale properties of a single object + + The the object is located + The Local ID of the object + One of the options from the enum + The price of the object + + + + Sets the sale properties of multiple objects + + The the objects are located + An array containing the Local IDs of the objects + One of the options from the enum + The price of the object + + + + Deselect a single object + + The the object is located + The Local ID of the object + + + + Deselect multiple objects. + + The the objects are located + An array containing the Local IDs of the objects + + + + Perform a click action on an object + + The the object is located + The Local ID of the object + + + + Perform a click action (Grab) on a single object + + The the object is located + The Local ID of the object + The texture coordinates to touch + The surface coordinates to touch + The face of the position to touch + The region coordinates of the position to touch + The surface normal of the position to touch (A normal is a vector perpindicular to the surface) + The surface binormal of the position to touch (A binormal is a vector tangen to the surface + pointing along the U direction of the tangent space + + + + Create (rez) a new prim object in a simulator + + A reference to the object to place the object in + Data describing the prim object to rez + Group ID that this prim will be set to, or UUID.Zero if you + do not want the object to be associated with a specific group + An approximation of the position at which to rez the prim + Scale vector to size this prim + Rotation quaternion to rotate this prim + Due to the way client prim rezzing is done on the server, + the requested position for an object is only close to where the prim + actually ends up. If you desire exact placement you'll need to + follow up by moving the object after it has been created. This + function will not set textures, light and flexible data, or other + extended primitive properties + + + + Create (rez) a new prim object in a simulator + + A reference to the object to place the object in + Data describing the prim object to rez + Group ID that this prim will be set to, or UUID.Zero if you + do not want the object to be associated with a specific group + An approximation of the position at which to rez the prim + Scale vector to size this prim + Rotation quaternion to rotate this prim + Specify the + Due to the way client prim rezzing is done on the server, + the requested position for an object is only close to where the prim + actually ends up. If you desire exact placement you'll need to + follow up by moving the object after it has been created. This + function will not set textures, light and flexible data, or other + extended primitive properties + + + + Rez a Linden tree + + A reference to the object where the object resides + The size of the tree + The rotation of the tree + The position of the tree + The Type of tree + The of the group to set the tree to, + or UUID.Zero if no group is to be set + true to use the "new" Linden trees, false to use the old + + + + Rez grass and ground cover + + A reference to the object where the object resides + The size of the grass + The rotation of the grass + The position of the grass + The type of grass from the enum + The of the group to set the tree to, + or UUID.Zero if no group is to be set + + + + Set the textures to apply to the faces of an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The texture data to apply + + + + Set the textures to apply to the faces of an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The texture data to apply + A media URL (not used) + + + + Set the Light data on an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + A object containing the data to set + + + + Set the flexible data on an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + A object containing the data to set + + + + Set the sculptie texture and data on an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + A object containing the data to set + + + + Unset additional primitive parameters on an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The extra parameters to set + + + + Link multiple prims into a linkset + + A reference to the object where the objects reside + An array which contains the IDs of the objects to link + The last object in the array will be the root object of the linkset TODO: Is this true? + + + + Delink/Unlink multiple prims from a linkset + + A reference to the object where the objects reside + An array which contains the IDs of the objects to delink + + + + Change the rotation of an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The new rotation of the object + + + + Set the name of an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + A string containing the new name of the object + + + + Set the name of multiple objects + + A reference to the object where the objects reside + An array which contains the IDs of the objects to change the name of + An array which contains the new names of the objects + + + + Set the description of an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + A string containing the new description of the object + + + + Set the descriptions of multiple objects + + A reference to the object where the objects reside + An array which contains the IDs of the objects to change the description of + An array which contains the new descriptions of the objects + + + + Attach an object to this avatar + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The point on the avatar the object will be attached + The rotation of the attached object + + + + Drop an attached object from this avatar + + A reference to the + object where the objects reside. This will always be the simulator the avatar is currently in + + The object's ID which is local to the simulator the object is in + + + + Detach an object from yourself + + A reference to the + object where the objects reside + + This will always be the simulator the avatar is currently in + + An array which contains the IDs of the objects to detach + + + + Change the position of an object, Will change position of entire linkset + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The new position of the object + + + + Change the position of an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The new position of the object + if true, will change position of (this) child prim only, not entire linkset + + + + Change the Scale (size) of an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The new scale of the object + If true, will change scale of this prim only, not entire linkset + True to resize prims uniformly + + + + Change the Rotation of an object that is either a child or a whole linkset + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The new scale of the object + If true, will change rotation of this prim only, not entire linkset + + + + Send a Multiple Object Update packet to change the size, scale or rotation of a primitive + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The new rotation, size, or position of the target object + The flags from the Enum + + + + Deed an object (prim) to a group, Object must be shared with group which + can be accomplished with SetPermissions() + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The of the group to deed the object to + + + + Deed multiple objects (prims) to a group, Objects must be shared with group which + can be accomplished with SetPermissions() + + A reference to the object where the object resides + An array which contains the IDs of the objects to deed + The of the group to deed the object to + + + + Set the permissions on multiple objects + + A reference to the object where the objects reside + An array which contains the IDs of the objects to set the permissions on + The new Who mask to set + Which permission to modify + The new state of permission + + + + Request additional properties for an object + + A reference to the object where the object resides + + + + + Request additional properties for an object + + A reference to the object where the object resides + Absolute UUID of the object + Whether to require server acknowledgement of this request + + + + Set the ownership of a list of objects to the specified group + + A reference to the object where the objects reside + An array which contains the IDs of the objects to set the group id on + The Groups ID + + + + Update current URL of the previously set prim media + + UUID of the prim + Set current URL to this + Prim face number + Simulator in which prim is located + + + + Set object media + + UUID of the prim + Array the length of prims number of faces. Null on face indexes where there is + no media, on faces which contain the media + Simulatior in which prim is located + + + + Retrieve information about object media + + UUID of the primitive + Simulator where prim is located + Call this callback when done + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + + A terse object update, used when a transformation matrix or + velocity/acceleration for an object changes but nothing else + (scale/position/rotation/acceleration/velocity) + + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + + + + + + + + + + Setup construction data for a basic primitive shape + + Primitive shape to construct + Construction data that can be plugged into a + + + + + + + + + + + + + + + + + + + + Set the Shape data of an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + Data describing the prim shape + + + + Set the Material data of an object + + A reference to the object where the object resides + The objects ID which is local to the simulator the object is in + The new material of the object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Provides data for the event + The event occurs when the simulator sends + an containing a Primitive, Foliage or Attachment data + Note 1: The event will not be raised when the object is an Avatar + Note 2: It is possible for the to be + raised twice for the same object if for example the primitive moved to a new simulator, then returned to the current simulator or + if an Avatar crosses the border into a new simulator and returns to the current simulator + + + The following code example uses the , , and + properties to display new Primitives and Attachments on the window. + + // Subscribe to the event that gives us prim and foliage information + Client.Objects.ObjectUpdate += Objects_ObjectUpdate; + + + private void Objects_ObjectUpdate(object sender, PrimEventArgs e) + { + Console.WriteLine("Primitive {0} {1} in {2} is an attachment {3}", e.Prim.ID, e.Prim.LocalID, e.Simulator.Name, e.IsAttachment); + } + + + + + + + + Get the simulator the originated from + + + Get the details + + + true if the did not exist in the dictionary before this update (always true if object tracking has been disabled) + + + true if the is attached to an + + + Get the simulator Time Dilation + + + + Construct a new instance of the PrimEventArgs class + + The simulator the object originated from + The Primitive + The simulator time dilation + The prim was not in the dictionary before this update + true if the primitive represents an attachment to an agent + + + Provides data for the event + The event occurs when the simulator sends + an containing Avatar data + Note 1: The event will not be raised when the object is an Avatar + Note 2: It is possible for the to be + raised twice for the same avatar if for example the avatar moved to a new simulator, then returned to the current simulator + + + The following code example uses the property to make a request for the top picks + using the method in the class to display the names + of our own agents picks listings on the window. + + // subscribe to the AvatarUpdate event to get our information + Client.Objects.AvatarUpdate += Objects_AvatarUpdate; + Client.Avatars.AvatarPicksReply += Avatars_AvatarPicksReply; + + private void Objects_AvatarUpdate(object sender, AvatarUpdateEventArgs e) + { + // we only want our own data + if (e.Avatar.LocalID == Client.Self.LocalID) + { + // Unsubscribe from the avatar update event to prevent a loop + // where we continually request the picks every time we get an update for ourselves + Client.Objects.AvatarUpdate -= Objects_AvatarUpdate; + // make the top picks request through AvatarManager + Client.Avatars.RequestAvatarPicks(e.Avatar.ID); + } + } + + private void Avatars_AvatarPicksReply(object sender, AvatarPicksReplyEventArgs e) + { + // we'll unsubscribe from the AvatarPicksReply event since we now have the data + // we were looking for + Client.Avatars.AvatarPicksReply -= Avatars_AvatarPicksReply; + // loop through the dictionary and extract the names of the top picks from our profile + foreach (var pickName in e.Picks.Values) + { + Console.WriteLine(pickName); + } + } + + + + + + + Get the simulator the object originated from + + + Get the data + + + Get the simulator time dilation + + + true if the did not exist in the dictionary before this update (always true if avatar tracking has been disabled) + + + + Construct a new instance of the AvatarUpdateEventArgs class + + The simulator the packet originated from + The data + The simulator time dilation + The avatar was not in the dictionary before this update + + + Get the simulator the object originated from + + + Get the data + + + Get source + + + + Construct a new instance of the ParticleUpdateEventArgs class + + The simulator the packet originated from + The ParticleSystem data + The Primitive source + + + Provides additional primitive data for the event + The event occurs when the simulator sends + an containing additional details for a Primitive, Foliage data or Attachment data + The event is also raised when a request is + made. + + + The following code example uses the , and + + properties to display new attachments and send a request for additional properties containing the name of the + attachment then display it on the window. + + // Subscribe to the event that provides additional primitive details + Client.Objects.ObjectProperties += Objects_ObjectProperties; + + // handle the properties data that arrives + private void Objects_ObjectProperties(object sender, ObjectPropertiesEventArgs e) + { + Console.WriteLine("Primitive Properties: {0} Name is {1}", e.Properties.ObjectID, e.Properties.Name); + } + + + + + Get the simulator the object is located + + + Get the primitive properties + + + + Construct a new instance of the ObjectPropertiesEventArgs class + + The simulator the object is located + The primitive Properties + + + Provides additional primitive data for the event + The event occurs when the simulator sends + an containing additional details for a Primitive or Foliage data that is currently + being tracked in the dictionary + The event is also raised when a request is + made and is enabled + + + + Get the primitive details + + + + Construct a new instance of the ObjectPropertiesUpdatedEvenrArgs class + + The simulator the object is located + The Primitive + The primitive Properties + + + Provides additional primitive data, permissions and sale info for the event + The event occurs when the simulator sends + an containing additional details for a Primitive, Foliage data or Attachment. This includes + Permissions, Sale info, and other basic details on an object + The event is also raised when a request is + made, the viewer equivalent is hovering the mouse cursor over an object + + + + Get the simulator the object is located + + + + + + + + + Provides primitive data containing updated location, velocity, rotation, textures for the event + The event occurs when the simulator sends updated location, velocity, rotation, etc + + + + Get the simulator the object is located + + + Get the primitive details + + + + + + + + + + + + + + Get the simulator the object is located + + + Get the primitive details + + + + + + + + + + + + + + + Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the + event + + + Get the simulator the object is located + + + The LocalID of the object + + + Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the + event + + + Get the simulator the object is located + + + The LocalID of the object + + + + Provides updates sit position data + + + + Get the simulator the object is located + + + + + + + + + + + + + + + + + Get the simulator the object is located + + + + + + + + + + + + + Indicates if the operation was successful + + + + + Media version string + + + + + Array of media entries indexed by face number + + + + + Set when simulator sends us infomation on primitive's physical properties + + + + Simulator where the message originated + + + Updated physical properties + + + + Constructor + + Simulator where the message originated + Updated physical properties + + + Size of the byte array used to store raw packet data + + + Raw packet data buffer + + + Length of the data to transmit + + + EndPoint of the remote host + + + + Create an allocated UDP packet buffer for receiving a packet + + + + + Create an allocated UDP packet buffer for sending a packet + + EndPoint of the remote host + + + + Create an allocated UDP packet buffer for sending a packet + + EndPoint of the remote host + Size of the buffer to allocate for packet data + + + + Object pool for packet buffers. This is used to allocate memory for all + incoming and outgoing packets, and zerocoding buffers for those packets + + + + + Initialize the object pool in client mode + + Server to connect to + + + + + + Initialize the object pool in server mode + + + + + + + Returns a packet buffer with EndPoint set if the buffer is in + client mode, or with EndPoint set to null in server mode + + Initialized UDPPacketBuffer object + + + + Default constructor + + + + + Check a packet buffer out of the pool + + A packet buffer object + + + + Returns an instance of the class that has been checked out of the Object Pool. + + + + + Checks the instance back into the object pool + + + + + Creates a new instance of the ObjectPoolBase class. Initialize MUST be called + after using this constructor. + + + + + Creates a new instance of the ObjectPool Base class. + + The object pool is composed of segments, which + are allocated whenever the size of the pool is exceeded. The number of items + in a segment should be large enough that allocating a new segmeng is a rare + thing. For example, on a server that will have 10k people logged in at once, + the receive buffer object pool should have segment sizes of at least 1000 + byte arrays per segment. + + The minimun number of segments that may exist. + Perform a full GC.Collect whenever a segment is allocated, and then again after allocation to compact the heap. + The frequency which segments are checked to see if they're eligible for cleanup. + + + + Forces the segment cleanup algorithm to be run. This method is intended + primarly for use from the Unit Test libraries. + + + + + Responsible for allocate 1 instance of an object that will be stored in a segment. + + An instance of whatever objec the pool is pooling. + + + + Checks in an instance of T owned by the object pool. This method is only intended to be called + by the WrappedObject class. + + The segment from which the instance is checked out. + The instance of T to check back into the segment. + + + + Checks an instance of T from the pool. If the pool is not sufficient to + allow the checkout, a new segment is created. + + A WrappedObject around the instance of T. To check + the instance back into the segment, be sureto dispose the WrappedObject + when finished. + + + + The total number of segments created. Intended to be used by the Unit Tests. + + + + + The number of items that are in a segment. Items in a segment + are all allocated at the same time, and are hopefully close to + each other in the managed heap. + + + + + The minimum number of segments. When segments are reclaimed, + this number of segments will always be left alone. These + segments are allocated at startup. + + + + + The age a segment must be before it's eligible for cleanup. + This is used to prevent thrash, and typical values are in + the 5 minute range. + + + + + The frequence which the cleanup thread runs. This is typically + expected to be in the 5 minute range. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The ObservableDictionary class is used for storing key/value pairs. It has methods for firing + events to subscribers when items are added, removed, or changed. + + Key + Value + + + + A dictionary of callbacks to fire when specified action occurs + + + + + Register a callback to be fired when an action occurs + + The action + The callback to fire + + + + Unregister a callback + + The action + The callback to fire + + + + + + + + + + Internal dictionary that this class wraps around. Do not + modify or enumerate the contents of this dictionary without locking + + + + Gets the number of Key/Value pairs contained in the + + + + + Initializes a new instance of the Class + with the specified key/value, has the default initial capacity. + + + + // initialize a new ObservableDictionary named testDict with a string as the key and an int as the value. + public ObservableDictionary<string, int> testDict = new ObservableDictionary<string, int>(); + + + + + + Initializes a new instance of the Class + with the specified key/value, With its initial capacity specified. + + Initial size of dictionary + + + // initialize a new ObservableDictionary named testDict with a string as the key and an int as the value, + // initially allocated room for 10 entries. + public ObservableDictionary<string, int> testDict = new ObservableDictionary<string, int>(10); + + + + + + Try to get entry from the with specified key + + Key to use for lookup + Value returned + if specified key exists, if not found + + + // find your avatar using the Simulator.ObjectsAvatars ObservableDictionary: + Avatar av; + if (Client.Network.CurrentSim.ObjectsAvatars.TryGetValue(Client.Self.AgentID, out av)) + Console.WriteLine("Found Avatar {0}", av.Name); + + + + + + + Finds the specified match. + + The match. + Matched value + + + // use a delegate to find a prim in the ObjectsPrimitives ObservableDictionary + // with the ID 95683496 + uint findID = 95683496; + Primitive findPrim = sim.ObjectsPrimitives.Find( + delegate(Primitive prim) { return prim.ID == findID; }); + + + + + Find All items in an + return matching items. + a containing found items. + + Find All prims within 20 meters and store them in a List + + int radius = 20; + List<Primitive> prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll( + delegate(Primitive prim) { + Vector3 pos = prim.Position; + return ((prim.ParentID == 0) && (pos != Vector3.Zero) && (Vector3.Distance(pos, location) < radius)); + } + ); + + + + + Find All items in an + return matching keys. + a containing found keys. + + Find All keys which also exist in another dictionary + + List<UUID> matches = myDict.FindAll( + delegate(UUID id) { + return myOtherDict.ContainsKey(id); + } + ); + + + + + Check if Key exists in Dictionary + Key to check for + if found, otherwise + + + Check if Value exists in Dictionary + Value to check for + if found, otherwise + + + + Adds the specified key to the dictionary, dictionary locking is not performed, + + + The key + The value + + + + Removes the specified key, dictionary locking is not performed + + The key. + if successful, otherwise + + + + Indexer for the dictionary + + The key + The value + + + + Clear the contents of the dictionary + + + + + Enumerator for iterating dictionary entries + + + + + + Provides helper methods for parallelizing loops + + + + + Executes a for loop in which iterations may run in parallel + + The loop will be started at this index + The loop will be terminated before this index is reached + Method body to run for each iteration of the loop + + + + Executes a for loop in which iterations may run in parallel + + The number of concurrent execution threads to run + The loop will be started at this index + The loop will be terminated before this index is reached + Method body to run for each iteration of the loop + + + + Executes a foreach loop in which iterations may run in parallel + + Object type that the collection wraps + An enumerable collection to iterate over + Method body to run for each object in the collection + + + + Executes a foreach loop in which iterations may run in parallel + + Object type that the collection wraps + The number of concurrent execution threads to run + An enumerable collection to iterate over + Method body to run for each object in the collection + + + + Executes a series of tasks in parallel + + A series of method bodies to execute + + + + Executes a series of tasks in parallel + + The number of concurrent execution threads to run + A series of method bodies to execute + + + + Type of return to use when returning objects from a parcel + + + + + + + Return objects owned by parcel owner + + + Return objects set to group + + + Return objects not owned by parcel owner or set to group + + + Return a specific list of objects on parcel + + + Return objects that are marked for-sale + + + + Blacklist/Whitelist flags used in parcels Access List + + + + Agent is denied access + + + Agent is granted access + + + + The result of a request for parcel properties + + + + No matches were found for the request + + + Request matched a single parcel + + + Request matched multiple parcels + + + + Flags used in the ParcelAccessListRequest packet to specify whether + we want the access list (whitelist), ban list (blacklist), or both + + + + Request the access list + + + Request the ban list + + + Request both White and Black lists + + + + Sequence ID in ParcelPropertiesReply packets (sent when avatar + tries to cross a parcel border) + + + + Parcel is currently selected + + + Parcel restricted to a group the avatar is not a + member of + + + Avatar is banned from the parcel + + + Parcel is restricted to an access list that the + avatar is not on + + + Response to hovering over a parcel + + + + The tool to use when modifying terrain levels + + + + Level the terrain + + + Raise the terrain + + + Lower the terrain + + + Smooth the terrain + + + Add random noise to the terrain + + + Revert terrain to simulator default + + + + The tool size to use when changing terrain levels + + + + Small + + + Medium + + + Large + + + + Reasons agent is denied access to a parcel on the simulator + + + + Agent is not denied, access is granted + + + Agent is not a member of the group set for the parcel, or which owns the parcel + + + Agent is not on the parcels specific allow list + + + Agent is on the parcels ban list + + + Unknown + + + Agent is not age verified and parcel settings deny access to non age verified avatars + + + + Parcel overlay type. This is used primarily for highlighting and + coloring which is why it is a single integer instead of a set of + flags + + These values seem to be poorly thought out. The first three + bits represent a single value, not flags. For example Auction (0x05) is + not a combination of OwnedByOther (0x01) and ForSale(0x04). However, + the BorderWest and BorderSouth values are bit flags that get attached + to the value stored in the first three bits. Bits four, five, and six + are unused + + + Public land + + + Land is owned by another avatar + + + Land is owned by a group + + + Land is owned by the current avatar + + + Land is for sale + + + Land is being auctioned + + + Land is private + + + To the west of this area is a parcel border + + + To the south of this area is a parcel border + + + + Various parcel properties + + + + No flags set + + + Allow avatars to fly (a client-side only restriction) + + + Allow foreign scripts to run + + + This parcel is for sale + + + Allow avatars to create a landmark on this parcel + + + Allows all avatars to edit the terrain on this parcel + + + Avatars have health and can take damage on this parcel. + If set, avatars can be killed and sent home here + + + Foreign avatars can create objects here + + + All objects on this parcel can be purchased + + + Access is restricted to a group + + + Access is restricted to a whitelist + + + Ban blacklist is enabled + + + Unknown + + + List this parcel in the search directory + + + Allow personally owned parcels to be deeded to group + + + If Deeded, owner contributes required tier to group parcel is deeded to + + + Restrict sounds originating on this parcel to the + parcel boundaries + + + Objects on this parcel are sold when the land is + purchsaed + + + Allow this parcel to be published on the web + + + The information for this parcel is mature content + + + The media URL is an HTML page + + + The media URL is a raw HTML string + + + Restrict foreign object pushes + + + Ban all non identified/transacted avatars + + + Allow group-owned scripts to run + + + Allow object creation by group members or group + objects + + + Allow all objects to enter this parcel + + + Only allow group and owner objects to enter this parcel + + + Voice Enabled on this parcel + + + Use Estate Voice channel for Voice on this parcel + + + Deny Age Unverified Users + + + + Parcel ownership status + + + + Placeholder + + + Parcel is leased (owned) by an avatar or group + + + Parcel is in process of being leased (purchased) by an avatar or group + + + Parcel has been abandoned back to Governor Linden + + + + Category parcel is listed in under search + + + + No assigned category + + + Linden Infohub or public area + + + Adult themed area + + + Arts and Culture + + + Business + + + Educational + + + Gaming + + + Hangout or Club + + + Newcomer friendly + + + Parks and Nature + + + Residential + + + Shopping + + + Not Used? + + + Other + + + Not an actual category, only used for queries + + + + Type of teleport landing for a parcel + + + + Unset, simulator default + + + Specific landing point set for this parcel + + + No landing point set, direct teleports enabled for + this parcel + + + + Parcel Media Command used in ParcelMediaCommandMessage + + + + Stop the media stream and go back to the first frame + + + Pause the media stream (stop playing but stay on current frame) + + + Start the current media stream playing and stop when the end is reached + + + Start the current media stream playing, + loop to the beginning when the end is reached and continue to play + + + Specifies the texture to replace with video + If passing the key of a texture, it must be explicitly typecast as a key, + not just passed within double quotes. + + + Specifies the movie URL (254 characters max) + + + Specifies the time index at which to begin playing + + + Specifies a single agent to apply the media command to + + + Unloads the stream. While the stop command sets the texture to the first frame of the movie, + unload resets it to the real texture that the movie was replacing. + + + Turn on/off the auto align feature, similar to the auto align checkbox in the parcel media properties + (NOT to be confused with the "align" function in the textures view of the editor!) Takes TRUE or FALSE as parameter. + + + Allows a Web page or image to be placed on a prim (1.19.1 RC0 and later only). + Use "text/html" for HTML. + + + Resizes a Web page to fit on x, y pixels (1.19.1 RC0 and later only). + This might still not be working + + + Sets a description for the media being displayed (1.19.1 RC0 and later only). + + + + Some information about a parcel of land returned from a DirectoryManager search + + + + Global Key of record + + + Parcel Owners + + + Name field of parcel, limited to 128 characters + + + Description field of parcel, limited to 256 characters + + + Total Square meters of parcel + + + Total area billable as Tier, for group owned land this will be 10% less than ActualArea + + + True of parcel is in Mature simulator + + + Grid global X position of parcel + + + Grid global Y position of parcel + + + Grid global Z position of parcel (not used) + + + Name of simulator parcel is located in + + + Texture of parcels display picture + + + Float representing calculated traffic based on time spent on parcel by avatars + + + Sale price of parcel (not used) + + + Auction ID of parcel + + + + Parcel Media Information + + + + A byte, if 0x1 viewer should auto scale media to fit object + + + A boolean, if true the viewer should loop the media + + + The Asset UUID of the Texture which when applied to a + primitive will display the media + + + A URL which points to any Quicktime supported media type + + + A description of the media + + + An Integer which represents the height of the media + + + An integer which represents the width of the media + + + A string which contains the mime type of the media + + + + Parcel of land, a portion of virtual real estate in a simulator + + + + The total number of contiguous 4x4 meter blocks your agent owns within this parcel + + + The total number of contiguous 4x4 meter blocks contained in this parcel owned by a group or agent other than your own + + + Deprecated, Value appears to always be 0 + + + Simulator-local ID of this parcel + + + UUID of the owner of this parcel + + + Whether the land is deeded to a group or not + + + + + + Date land was claimed + + + Appears to always be zero + + + This field is no longer used + + + Minimum corner of the axis-aligned bounding box for this + parcel + + + Maximum corner of the axis-aligned bounding box for this + parcel + + + Bitmap describing land layout in 4x4m squares across the + entire region + + + Total parcel land area + + + + + + Maximum primitives across the entire simulator owned by the same agent or group that owns this parcel that can be used + + + Total primitives across the entire simulator calculated by combining the allowed prim counts for each parcel + owned by the agent or group that owns this parcel + + + Maximum number of primitives this parcel supports + + + Total number of primitives on this parcel + + + For group-owned parcels this indicates the total number of prims deeded to the group, + for parcels owned by an individual this inicates the number of prims owned by the individual + + + Total number of primitives owned by the parcel group on + this parcel, or for parcels owned by an individual with a group set the + total number of prims set to that group. + + + Total number of prims owned by other avatars that are not set to group, or not the parcel owner + + + A bonus multiplier which allows parcel prim counts to go over times this amount, this does not affect + the max prims per simulator. e.g: 117 prim parcel limit x 1.5 bonus = 175 allowed + + + Autoreturn value in minutes for others' objects + + + + + + Sale price of the parcel, only useful if ForSale is set + The SalePrice will remain the same after an ownership + transfer (sale), so it can be used to see the purchase price after + a sale if the new owner has not changed it + + + Parcel Name + + + Parcel Description + + + URL For Music Stream + + + + + + Price for a temporary pass + + + How long is pass valid for + + + + + + Key of authorized buyer + + + Key of parcel snapshot + + + The landing point location + + + The landing point LookAt + + + The type of landing enforced from the enum + + + + + + + + + + + + Access list of who is whitelisted on this + parcel + + + Access list of who is blacklisted on this + parcel + + + TRUE of region denies access to age unverified users + + + true to obscure (hide) media url + + + true to obscure (hide) music url + + + A struct containing media details + + + + Displays a parcel object in string format + + string containing key=value pairs of a parcel object + + + + Defalt constructor + + Local ID of this parcel + + + + Update the simulator with any local changes to this Parcel object + + Simulator to send updates to + Whether we want the simulator to confirm + the update with a reply packet or not + + + + Set Autoreturn time + + Simulator to send the update to + + + + Parcel (subdivided simulator lots) subsystem + + + + + Parcel Accesslist + + + + Agents + + + + + + Flags for specific entry in white/black lists + + + + Owners of primitives on parcel + + + + Prim Owners + + + True of owner is group + + + Total count of prims owned by OwnerID + + + true of OwnerID is currently online and is not a group + + + The date of the most recent prim left by OwnerID + + + + Called once parcel resource usage information has been collected + + Indicates if operation was successfull + Parcel resource usage information + + + The event subscribers. null if no subcribers + + + Raises the ParcelDwellReply event + A ParcelDwellReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the ParcelInfoReply event + A ParcelInfoReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the ParcelProperties event + A ParcelPropertiesEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the ParcelAccessListReply event + A ParcelAccessListReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the ParcelObjectOwnersReply event + A ParcelObjectOwnersReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the SimParcelsDownloaded event + A SimParcelsDownloadedEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the ForceSelectObjectsReply event + A ForceSelectObjectsReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a request + + + The event subscribers. null if no subcribers + + + Raises the ParcelMediaUpdateReply event + A ParcelMediaUpdateReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds to a Parcel Update request + + + The event subscribers. null if no subcribers + + + Raises the ParcelMediaCommand event + A ParcelMediaCommandEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the parcel your agent is located sends a ParcelMediaCommand + + + + Default constructor + + A reference to the GridClient object + + + + Request basic information for a single parcel + + Simulator-local ID of the parcel + + + + Request properties of a single parcel + + Simulator containing the parcel + Simulator-local ID of the parcel + An arbitrary integer that will be returned + with the ParcelProperties reply, useful for distinguishing between + multiple simultaneous requests + + + + Request the access list for a single parcel + + Simulator containing the parcel + Simulator-local ID of the parcel + An arbitrary integer that will be returned + with the ParcelAccessList reply, useful for distinguishing between + multiple simultaneous requests + + + + + Request properties of parcels using a bounding box selection + + Simulator containing the parcel + Northern boundary of the parcel selection + Eastern boundary of the parcel selection + Southern boundary of the parcel selection + Western boundary of the parcel selection + An arbitrary integer that will be returned + with the ParcelProperties reply, useful for distinguishing between + different types of parcel property requests + A boolean that is returned with the + ParcelProperties reply, useful for snapping focus to a single + parcel + + + + Request all simulator parcel properties (used for populating the Simulator.Parcels + dictionary) + + Simulator to request parcels from (must be connected) + + + + Request all simulator parcel properties (used for populating the Simulator.Parcels + dictionary) + + Simulator to request parcels from (must be connected) + If TRUE, will force a full refresh + Number of milliseconds to pause in between each request + + + + Request the dwell value for a parcel + + Simulator containing the parcel + Simulator-local ID of the parcel + + + + Send a request to Purchase a parcel of land + + The Simulator the parcel is located in + The parcels region specific local ID + true if this parcel is being purchased by a group + The groups + true to remove tier contribution if purchase is successful + The parcels size + The purchase price of the parcel + + + + + Reclaim a parcel of land + + The simulator the parcel is in + The parcels region specific local ID + + + + Deed a parcel to a group + + The simulator the parcel is in + The parcels region specific local ID + The groups + + + + Request prim owners of a parcel of land. + + Simulator parcel is in + The parcels region specific local ID + + + + Return objects from a parcel + + Simulator parcel is in + The parcels region specific local ID + the type of objects to return, + A list containing object owners s to return + + + + Subdivide (split) a parcel + + + + + + + + + + Join two parcels of land creating a single parcel + + + + + + + + + + Get a parcels LocalID + + Simulator parcel is in + Vector3 position in simulator (Z not used) + 0 on failure, or parcel LocalID on success. + A call to Parcels.RequestAllSimParcels is required to populate map and + dictionary. + + + + Terraform (raise, lower, etc) an area or whole parcel of land + + Simulator land area is in. + LocalID of parcel, or -1 if using bounding box + From Enum, Raise, Lower, Level, Smooth, Etc. + Size of area to modify + true on successful request sent. + Settings.STORE_LAND_PATCHES must be true, + Parcel information must be downloaded using RequestAllSimParcels() + + + + Terraform (raise, lower, etc) an area or whole parcel of land + + Simulator land area is in. + west border of area to modify + south border of area to modify + east border of area to modify + north border of area to modify + From Enum, Raise, Lower, Level, Smooth, Etc. + Size of area to modify + true on successful request sent. + Settings.STORE_LAND_PATCHES must be true, + Parcel information must be downloaded using RequestAllSimParcels() + + + + Terraform (raise, lower, etc) an area or whole parcel of land + + Simulator land area is in. + LocalID of parcel, or -1 if using bounding box + west border of area to modify + south border of area to modify + east border of area to modify + north border of area to modify + From Enum, Raise, Lower, Level, Smooth, Etc. + Size of area to modify + How many meters + or - to lower, 1 = 1 meter + true on successful request sent. + Settings.STORE_LAND_PATCHES must be true, + Parcel information must be downloaded using RequestAllSimParcels() + + + + Terraform (raise, lower, etc) an area or whole parcel of land + + Simulator land area is in. + LocalID of parcel, or -1 if using bounding box + west border of area to modify + south border of area to modify + east border of area to modify + north border of area to modify + From Enum, Raise, Lower, Level, Smooth, Etc. + Size of area to modify + How many meters + or - to lower, 1 = 1 meter + Height at which the terraform operation is acting at + + + + Sends a request to the simulator to return a list of objects owned by specific owners + + Simulator local ID of parcel + Owners, Others, Etc + List containing keys of avatars objects to select; + if List is null will return Objects of type selectType + Response data is returned in the event + + + + Eject and optionally ban a user from a parcel + + target key of avatar to eject + true to also ban target + + + + Freeze or unfreeze an avatar over your land + + target key to freeze + true to freeze, false to unfreeze + + + + Abandon a parcel of land + + Simulator parcel is in + Simulator local ID of parcel + + + + Requests the UUID of the parcel in a remote region at a specified location + + Location of the parcel in the remote region + Remote region handle + Remote region UUID + If successful UUID of the remote parcel, UUID.Zero otherwise + + + + Retrieves information on resources used by the parcel + + UUID of the parcel + Should per object resource usage be requested + Callback invoked when the request is complete + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event + + + Contains a parcels dwell data returned from the simulator in response to an + + + Get the global ID of the parcel + + + Get the simulator specific ID of the parcel + + + Get the calculated dwell + + + + Construct a new instance of the ParcelDwellReplyEventArgs class + + The global ID of the parcel + The simulator specific ID of the parcel + The calculated dwell for the parcel + + + Contains basic parcel information data returned from the + simulator in response to an request + + + Get the object containing basic parcel info + + + + Construct a new instance of the ParcelInfoReplyEventArgs class + + The object containing basic parcel info + + + Contains basic parcel information data returned from the simulator in response to an request + + + Get the simulator the parcel is located in + + + Get the object containing the details + If Result is NoData, this object will not contain valid data + + + Get the result of the request + + + Get the number of primitieves your agent is + currently selecting and or sitting on in this parcel + + + Get the user assigned ID used to correlate a request with + these results + + + TODO: + + + + Construct a new instance of the ParcelPropertiesEventArgs class + + The object containing the details + The object containing the details + The result of the request + The number of primitieves your agent is + currently selecting and or sitting on in this parcel + The user assigned ID used to correlate a request with + these results + TODO: + + + Contains blacklist and whitelist data returned from the simulator in response to an request + + + Get the simulator the parcel is located in + + + Get the user assigned ID used to correlate a request with + these results + + + Get the simulator specific ID of the parcel + + + TODO: + + + Get the list containing the white/blacklisted agents for the parcel + + + + Construct a new instance of the ParcelAccessListReplyEventArgs class + + The simulator the parcel is located in + The user assigned ID used to correlate a request with + these results + The simulator specific ID of the parcel + TODO: + The list containing the white/blacklisted agents for the parcel + + + Contains blacklist and whitelist data returned from the + simulator in response to an request + + + Get the simulator the parcel is located in + + + Get the list containing prim ownership counts + + + + Construct a new instance of the ParcelObjectOwnersReplyEventArgs class + + The simulator the parcel is located in + The list containing prim ownership counts + + + Contains the data returned when all parcel data has been retrieved from a simulator + + + Get the simulator the parcel data was retrieved from + + + A dictionary containing the parcel data where the key correlates to the ParcelMap entry + + + Get the multidimensional array containing a x,y grid mapped + to each 64x64 parcel's LocalID. + + + + Construct a new instance of the SimParcelsDownloadedEventArgs class + + The simulator the parcel data was retrieved from + The dictionary containing the parcel data + The multidimensional array containing a x,y grid mapped + to each 64x64 parcel's LocalID. + + + Contains the data returned when a request + + + Get the simulator the parcel data was retrieved from + + + Get the list of primitive IDs + + + true if the list is clean and contains the information + only for a given request + + + + Construct a new instance of the ForceSelectObjectsReplyEventArgs class + + The simulator the parcel data was retrieved from + The list of primitive IDs + true if the list is clean and contains the information + only for a given request + + + Contains data when the media data for a parcel the avatar is on changes + + + Get the simulator the parcel media data was updated in + + + Get the updated media information + + + + Construct a new instance of the ParcelMediaUpdateReplyEventArgs class + + the simulator the parcel media data was updated in + The updated media information + + + Contains the media command for a parcel the agent is currently on + + + Get the simulator the parcel media command was issued in + + + + + + + + + Get the media command that was sent + + + + + + + Construct a new instance of the ParcelMediaCommandEventArgs class + + The simulator the parcel media command was issued in + + + The media command that was sent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Class for controlling various system settings. + + Some values are readonly because they affect things that + happen when the GridClient object is initialized, so changing them at + runtime won't do any good. Non-readonly values may affect things that + happen at login or dynamically + + + Main grid login server + + + Beta grid login server + + + The relative directory where external resources are kept + + + Login server to connect to + + + IP Address the client will bind to + + + Use XML-RPC Login or LLSD Login, default is XML-RPC Login + + + + Maximum number of HTTP connections to open to a particular endpoint. + + + An endpoint is defined as a commbination of network address and port. This is used for Caps. + This is a static variable which applies to all instances. + + + + + InventoryManager requests inventory information on login, + GridClient initializes an Inventory store for main inventory. + + + + + InventoryManager requests library information on login, + GridClient initializes an Inventory store for the library. + + + + + Use Caps for fetching inventory where available + + + + Number of milliseconds before an asset transfer will time + out + + + Number of milliseconds before a teleport attempt will time + out + + + Number of milliseconds before NetworkManager.Logout() will + time out + + + Number of milliseconds before a CAPS call will time out + Setting this too low will cause web requests time out and + possibly retry repeatedly + + + Number of milliseconds for xml-rpc to timeout + + + Milliseconds before a packet is assumed lost and resent + + + Milliseconds without receiving a packet before the + connection to a simulator is assumed lost + + + Milliseconds to wait for a simulator info request through + the grid interface + + + Number of milliseconds between sending pings to each sim + + + Number of milliseconds between sending camera updates + + + Number of milliseconds between updating the current + positions of moving, non-accelerating and non-colliding objects + + + Millisecond interval between ticks, where all ACKs are + sent out and the age of unACKed packets is checked + + + The initial size of the packet inbox, where packets are + stored before processing + + + Maximum size of packet that we want to send over the wire + + + The maximum value of a packet sequence number before it + rolls over back to one + + + The maximum size of the sequence number archive, used to + check for resent and/or duplicate packets + + + Maximum number of queued ACKs to be sent before SendAcks() + is forced + + + Network stats queue length (seconds) + + + + Primitives will be reused when falling in/out of interest list (and shared between clients) + prims returning to interest list do not need re-requested + Helps also in not re-requesting prim.Properties for code that checks for a Properties == null per client + + + + + Pool parcel data between clients (saves on requesting multiple times when all clients may need it) + + + + + How long to preserve cached data when no client is connected to a simulator + The reason for setting it to something like 2 minutes is in case a client + is running back and forth between region edges or a sim is comming and going + + + + Enable/disable storing terrain heightmaps in the + TerrainManager + + + Enable/disable sending periodic camera updates + + + Enable/disable automatically setting agent appearance at + login and after sim crossing + + + Enable/disable automatically setting the bandwidth throttle + after connecting to each simulator + The default throttle uses the equivalent of the maximum + bandwidth setting in the official client. If you do not set a + throttle your connection will by default be throttled well below + the minimum values and you may experience connection problems + + + Enable/disable the sending of pings to monitor lag and + packet loss + + + Should we connect to multiple sims? This will allow + viewing in to neighboring simulators and sim crossings + (Experimental) + + + If true, all object update packets will be decoded in to + native objects. If false, only updates for our own agent will be + decoded. Registering an event handler will force objects for that + type to always be decoded. If this is disabled the object tracking + will have missing or partial prim and avatar information + + + If true, when a cached object check is received from the + server the full object info will automatically be requested + + + Whether to establish connections to HTTP capabilities + servers for simulators + + + Whether to decode sim stats + + + The capabilities servers are currently designed to + periodically return a 502 error which signals for the client to + re-establish a connection. Set this to true to log those 502 errors + + + If true, any reference received for a folder or item + the library is not aware of will automatically be fetched + + + If true, and SEND_AGENT_UPDATES is true, + AgentUpdate packets will continuously be sent out to give the bot + smoother movement and autopiloting + + + If true, currently visible avatars will be stored + in dictionaries inside Simulator.ObjectAvatars. + If false, a new Avatar or Primitive object will be created + each time an object update packet is received + + + If true, currently visible avatars will be stored + in dictionaries inside Simulator.ObjectPrimitives. + If false, a new Avatar or Primitive object will be created + each time an object update packet is received + + + If true, position and velocity will periodically be + interpolated (extrapolated, technically) for objects and + avatars that are being tracked by the library. This is + necessary to increase the accuracy of speed and position + estimates for simulated objects + + + + If true, utilization statistics will be tracked. There is a minor penalty + in CPU time for enabling this option. + + + + If true, parcel details will be stored in the + Simulator.Parcels dictionary as they are received + + + + If true, an incoming parcel properties reply will automatically send + a request for the parcel access list + + + + + if true, an incoming parcel properties reply will automatically send + a request for the traffic count. + + + + + If true, images, and other assets downloaded from the server + will be cached in a local directory + + + + Path to store cached texture data + + + Maximum size cached files are allowed to take on disk (bytes) + + + Default color used for viewer particle effects + + + Cost of uploading an asset + Read-only since this value is dynamically fetched at login + + + Maximum number of times to resend a failed packet + + + Throttle outgoing packet rate + + + UUID of a texture used by some viewers to indentify type of client used + + + + Download textures using GetTexture capability when available + + + + The maximum number of concurrent texture downloads allowed + Increasing this number will not necessarily increase texture retrieval times due to + simulator throttles + + + + The Refresh timer inteval is used to set the delay between checks for stalled texture downloads + + This is a static variable which applies to all instances + + + + Textures taking longer than this value will be flagged as timed out and removed from the pipeline + + + + + Get or set the minimum log level to output to the console by default + + If the library is not compiled with DEBUG defined and this level is set to DEBUG + You will get no output on the console. This behavior can be overriden by creating + a logger configuration file for log4net + + + + Attach avatar names to log messages + + + Log packet retransmission info + + + Log disk cache misses and other info + + + Constructor + Reference to a GridClient object + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + + Simulator (region) properties + + + + No flags set + + + Agents can take damage and be killed + + + Landmarks can be created here + + + Home position can be set in this sim + + + Home position is reset when an agent teleports away + + + Sun does not move + + + No object, land, etc. taxes + + + Disable heightmap alterations (agents can still plant + foliage) + + + Land cannot be released, sold, or purchased + + + All content is wiped nightly + + + Unknown: Related to the availability of an overview world map tile.(Think mainland images when zoomed out.) + + + Unknown: Related to region debug flags. Possibly to skip processing of agent interaction with world. + + + Region does not update agent prim interest lists. Internal debugging option. + + + No collision detection for non-agent objects + + + No scripts are ran + + + All physics processing is turned off + + + Region can be seen from other regions on world map. (Legacy world map option?) + + + Region can be seen from mainland on world map. (Legacy world map option?) + + + Agents not explicitly on the access list can visit the region. + + + Traffic calculations are not run across entire region, overrides parcel settings. + + + Flight is disabled (not currently enforced by the sim) + + + Allow direct (p2p) teleporting + + + Estate owner has temporarily disabled scripting + + + Restricts the usage of the LSL llPushObject function, applies to whole region. + + + Deny agents with no payment info on file + + + Deny agents with payment info on file + + + Deny agents who have made a monetary transaction + + + Parcels within the region may be joined or divided by anyone, not just estate owners/managers. + + + Abuse reports sent from within this region are sent to the estate owner defined email. + + + Region is Voice Enabled + + + Removes the ability from parcel owners to set their parcels to show in search. + + + Deny agents who have not been age verified from entering the region. + + + + Region protocol flags + + + + Nothing special + + + Region supports Server side Appearance + + + Viewer supports Server side Appearance + + + + Access level for a simulator + + + + Unknown or invalid access level + + + Trial accounts allowed + + + PG rating + + + Mature rating + + + Adult rating + + + Simulator is offline + + + Simulator does not exist + + + + + + + + + Simulator Statistics + + + + Total number of packets sent by this simulator to this agent + + + Total number of packets received by this simulator to this agent + + + Total number of bytes sent by this simulator to this agent + + + Total number of bytes received by this simulator to this agent + + + Time in seconds agent has been connected to simulator + + + Total number of packets that have been resent + + + Total number of resent packets recieved + + + Total number of pings sent to this simulator by this agent + + + Total number of ping replies sent to this agent by this simulator + + + + Incoming bytes per second + + It would be nice to have this claculated on the fly, but + this is far, far easier + + + + Outgoing bytes per second + + It would be nice to have this claculated on the fly, but + this is far, far easier + + + Time last ping was sent + + + ID of last Ping sent + + + + + + + + + Current time dilation of this simulator + + + Current Frames per second of simulator + + + Current Physics frames per second of simulator + + + + + + + + + + + + + + + + + + + + + + + + + + + Total number of objects Simulator is simulating + + + Total number of Active (Scripted) objects running + + + Number of agents currently in this simulator + + + Number of agents in neighbor simulators + + + Number of Active scripts running in this simulator + + + + + + + + + + + + Number of downloads pending + + + Number of uploads pending + + + + + + + + + Number of local uploads pending + + + Unacknowledged bytes in queue + + + A public reference to the client that this Simulator object + is attached to + + + A Unique Cache identifier for this simulator + + + The capabilities for this simulator + + + + + + The current version of software this simulator is running + + + + + + A 64x64 grid of parcel coloring values. The values stored + in this array are of the type + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true if your agent has Estate Manager rights on this region + + + + + + + + + + + + Statistics information for this simulator and the + connection to the simulator, calculated by the simulator itself + and the library + + + The regions Unique ID + + + The physical data center the simulator is located + Known values are: + + Dallas + Chandler + SF + + + + + The CPU Class of the simulator + Most full mainland/estate sims appear to be 5, + Homesteads and Openspace appear to be 501 + + + The number of regions sharing the same CPU as this one + "Full Sims" appear to be 1, Homesteads appear to be 4 + + + The billing product name + Known values are: + + Mainland / Full Region (Sku: 023) + Estate / Full Region (Sku: 024) + Estate / Openspace (Sku: 027) + Estate / Homestead (Sku: 029) + Mainland / Homestead (Sku: 129) (Linden Owned) + Mainland / Linden Homes (Sku: 131) + + + + + The billing product SKU + Known values are: + + 023 Mainland / Full Region + 024 Estate / Full Region + 027 Estate / Openspace + 029 Estate / Homestead + 129 Mainland / Homestead (Linden Owned) + 131 Linden Homes / Full Region + + + + + + Flags indicating which protocols this region supports + + + + The current sequence number for packets sent to this + simulator. Must be Interlocked before modifying. Only + useful for applications manipulating sequence numbers + + + + A thread-safe dictionary containing avatars in a simulator + + + + + A thread-safe dictionary containing primitives in a simulator + + + + + Provides access to an internal thread-safe dictionary containing parcel + information found in this simulator + + + + + Provides access to an internal thread-safe multidimensional array containing a x,y grid mapped + to each 64x64 parcel's LocalID. + + + + + Checks simulator parcel map to make sure it has downloaded all data successfully + + true if map is full (contains no 0's) + + + + Is it safe to send agent updates to this sim + AgentMovementComplete message received + + + + The IP address and port of the server + + + Whether there is a working connection to the simulator or + not + + + Coarse locations of avatars in this simulator + + + AvatarPositions key representing TrackAgent target + + + Indicates if UDP connection to the sim is fully established + + + Used internally to track sim disconnections + + + Event that is triggered when the simulator successfully + establishes a connection + + + Whether this sim is currently connected or not. Hooked up + to the property Connected + + + Coarse locations of avatars in this simulator + + + AvatarPositions key representing TrackAgent target + + + Sequence numbers of packets we've received + (for duplicate checking) + + + Packets we sent out that need ACKs from the simulator + + + Sequence number for pause/resume + + + Indicates if UDP connection to the sim is fully established + + + + + + Reference to the GridClient object + IPEndPoint of the simulator + handle of the simulator + + + + Called when this Simulator object is being destroyed + + + + + Attempt to connect to this simulator + + Whether to move our agent in to this sim or not + True if the connection succeeded or connection status is + unknown, false if there was a failure + + + + Initiates connection to the simulator + + Should we block until ack for this packet is recieved + + + + Disconnect from this simulator + + + + + Instructs the simulator to stop sending update (and possibly other) packets + + + + + Instructs the simulator to resume sending update packets (unpause) + + + + + Retrieve the terrain height at a given coordinate + + Sim X coordinate, valid range is from 0 to 255 + Sim Y coordinate, valid range is from 0 to 255 + The terrain height at the given point if the + lookup was successful, otherwise 0.0f + True if the lookup was successful, otherwise false + + + + Sends a packet + + Packet to be sent + + + + + + + + + Returns Simulator Name as a String + + + + + + + + + + + + + + + + + + + Sends out pending acknowledgements + + Number of ACKs sent + + + + Resend unacknowledged packets + + + + + Simulator handle + + + + + Number of GridClients using this datapool + + + + + Time that the last client disconnected from the simulator + + + + + The cache of prims used and unused in this simulator + + + + + Shared parcel info only when POOL_PARCEL_DATA == true + + + + + + + + + The event subscribers, null of no subscribers + + + Raises the AttachedSound Event + A AttachedSoundEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + sound + + + The event subscribers, null of no subscribers + + + Raises the AttachedSoundGainChange Event + A AttachedSoundGainChangeEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the SoundTrigger Event + A SoundTriggerEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + The event subscribers, null of no subscribers + + + Raises the PreloadSound Event + A PreloadSoundEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + Raised when the simulator sends us data containing + ... + + + + Construct a new instance of the SoundManager class, used for playing and receiving + sound assets + + A reference to the current GridClient instance + + + + Plays a sound in the current region at full volume from avatar position + + UUID of the sound to be played + + + + Plays a sound in the current region at full volume + + UUID of the sound to be played. + position for the sound to be played at. Normally the avatar. + + + + Plays a sound in the current region + + UUID of the sound to be played. + position for the sound to be played at. Normally the avatar. + volume of the sound, from 0.0 to 1.0 + + + + Plays a sound in the specified sim + + UUID of the sound to be played. + UUID of the sound to be played. + position for the sound to be played at. Normally the avatar. + volume of the sound, from 0.0 to 1.0 + + + + Play a sound asset + + UUID of the sound to be played. + handle id for the sim to be played in. + position for the sound to be played at. Normally the avatar. + volume of the sound, from 0.0 to 1.0 + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + + + Provides data for the event + The event occurs when the simulator sends + the sound data which emits from an agents attachment + + The following code example shows the process to subscribe to the event + and a stub to handle the data passed from the simulator + + // Subscribe to the AttachedSound event + Client.Sound.AttachedSound += Sound_AttachedSound; + + // process the data raised in the event here + private void Sound_AttachedSound(object sender, AttachedSoundEventArgs e) + { + // ... Process AttachedSoundEventArgs here ... + } + + + + + Simulator where the event originated + + + Get the sound asset id + + + Get the ID of the owner + + + Get the ID of the Object + + + Get the volume level + + + Get the + + + + Construct a new instance of the SoundTriggerEventArgs class + + Simulator where the event originated + The sound asset id + The ID of the owner + The ID of the object + The volume level + The + + + Provides data for the event + The event occurs when an attached sound + changes its volume level + + + Simulator where the event originated + + + Get the ID of the Object + + + Get the volume level + + + + Construct a new instance of the AttachedSoundGainChangedEventArgs class + + Simulator where the event originated + The ID of the Object + The new volume level + + + Provides data for the event + The event occurs when the simulator forwards + a request made by yourself or another agent to play either an asset sound or a built in sound + + Requests to play sounds where the is not one of the built-in + will require sending a request to download the sound asset before it can be played + + + The following code example uses the , + and + properties to display some information on a sound request on the window. + + // subscribe to the event + Client.Sound.SoundTrigger += Sound_SoundTrigger; + + // play the pre-defined BELL_TING sound + Client.Sound.SendSoundTrigger(Sounds.BELL_TING); + + // handle the response data + private void Sound_SoundTrigger(object sender, SoundTriggerEventArgs e) + { + Console.WriteLine("{0} played the sound {1} at volume {2}", + e.OwnerID, e.SoundID, e.Gain); + } + + + + + Simulator where the event originated + + + Get the sound asset id + + + Get the ID of the owner + + + Get the ID of the Object + + + Get the ID of the objects parent + + + Get the volume level + + + Get the regionhandle + + + Get the source position + + + + Construct a new instance of the SoundTriggerEventArgs class + + Simulator where the event originated + The sound asset id + The ID of the owner + The ID of the object + The ID of the objects parent + The volume level + The regionhandle + The source position + + + Provides data for the event + The event occurs when the simulator sends + the appearance data for an avatar + + The following code example uses the and + properties to display the selected shape of an avatar on the window. + + // subscribe to the event + Client.Avatars.AvatarAppearance += Avatars_AvatarAppearance; + + // handle the data when the event is raised + void Avatars_AvatarAppearance(object sender, AvatarAppearanceEventArgs e) + { + Console.WriteLine("The Agent {0} is using a {1} shape.", e.AvatarID, (e.VisualParams[31] > 0) : "male" ? "female") + } + + + + + Simulator where the event originated + + + Get the sound asset id + + + Get the ID of the owner + + + Get the ID of the Object + + + + Construct a new instance of the PreloadSoundEventArgs class + + Simulator where the event originated + The sound asset id + The ID of the owner + The ID of the object + + + + pre-defined built in sounds + + + + + + + + + + + + + + + + + + + + + + + + + + + + coins + + + cash register bell + + + + + + + + + rubber + + + plastic + + + flesh + + + wood splintering? + + + glass break + + + metal clunk + + + whoosh + + + shake + + + + + + ding + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A dictionary containing all pre-defined sounds + + A dictionary containing the pre-defined sounds, + where the key is the sounds ID, and the value is a string + containing a name to identify the purpose of the sound + + + X position of this patch + + + Y position of this patch + + + A 16x16 array of floats holding decompressed layer data + + + + Creates a LayerData packet for compressed land data given a full + simulator heightmap and an array of indices of patches to compress + + A 256 * 256 array of floating point values + specifying the height at each meter in the simulator + Array of indexes in the 16x16 grid of patches + for this simulator. For example if 1 and 17 are specified, patches + x=1,y=0 and x=1,y=1 are sent + + + + + Add a patch of terrain to a BitPacker + + BitPacker to write the patch to + Heightmap of the simulator, must be a 256 * + 256 float array + X offset of the patch to create, valid values are + from 0 to 15 + Y offset of the patch to create, valid values are + from 0 to 15 + + + The event subscribers. null if no subcribers + + + Raises the LandPatchReceived event + A LandPatchReceivedEventArgs object containing the + data returned from the simulator + + + Thread sync lock object + + + Raised when the simulator responds sends + + + + Default constructor + + + + + Simulator from that sent tha data + + + Sim coordinate of the patch + + + Sim coordinate of the patch + + + Size of tha patch + + + Heightmap for the patch + + + + The current status of a texture request as it moves through the pipeline or final result of a texture request. + + + + The initial state given to a request. Requests in this state + are waiting for an available slot in the pipeline + + + A request that has been added to the pipeline and the request packet + has been sent to the simulator + + + A request that has received one or more packets back from the simulator + + + A request that has received all packets back from the simulator + + + A request that has taken longer than + to download OR the initial packet containing the packet information was never received + + + The texture request was aborted by request of the agent + + + The simulator replied to the request that it was not able to find the requested texture + + + + A callback fired to indicate the status or final state of the requested texture. For progressive + downloads this will fire each time new asset data is returned from the simulator. + + The indicating either Progress for textures not fully downloaded, + or the final result of the request after it has been processed through the TexturePipeline + The object containing the Assets ID, raw data + and other information. For progressive rendering the will contain + the data from the beginning of the file. For failed, aborted and timed out requests it will contain + an empty byte array. + + + + Texture request download handler, allows a configurable number of download slots which manage multiple + concurrent texture downloads from the + + This class makes full use of the internal + system for full texture downloads. + + + + A request task containing information and status of a request as it is processed through the + + + + The current which identifies the current status of the request + + + The Unique Request ID, This is also the Asset ID of the texture being requested + + + The slot this request is occupying in the threadpoolSlots array + + + The ImageType of the request. + + + The callback to fire when the request is complete, will include + the and the + object containing the result data + + + If true, indicates the callback will be fired whenever new data is returned from the simulator. + This is used to progressively render textures as portions of the texture are received. + + + An object that maintains the data of an request thats in-process. + + + A dictionary containing all pending and in-process transfer requests where the Key is both the RequestID + and also the Asset Texture ID, and the value is an object containing the current state of the request and also + the asset data as it is being re-assembled + + + Holds the reference to the client object + + + Maximum concurrent texture requests allowed at a time + + + An array of objects used to manage worker request threads + + + An array of worker slots which shows the availablity status of the slot + + + The primary thread which manages the requests. + + + true if the TexturePipeline is currently running + + + A synchronization object used by the primary thread + + + A refresh timer used to increase the priority of stalled requests + + + Current number of pending and in-process transfers + + + + Default constructor, Instantiates a new copy of the TexturePipeline class + + Reference to the instantiated object + + + + Initialize callbacks required for the TexturePipeline to operate + + + + + Shutdown the TexturePipeline and cleanup any callbacks or transfers + + + + + Request a texture asset from the simulator using the system to + manage the requests and re-assemble the image from the packets received from the simulator + + The of the texture asset to download + The of the texture asset. + Use for most textures, or for baked layer texture assets + A float indicating the requested priority for the transfer. Higher priority values tell the simulator + to prioritize the request before lower valued requests. An image already being transferred using the can have + its priority changed by resending the request with the new priority value + Number of quality layers to discard. + This controls the end marker of the data sent + The packet number to begin the request at. A value of 0 begins the request + from the start of the asset texture + The callback to fire when the image is retrieved. The callback + will contain the result of the request and the texture asset data + If true, the callback will be fired for each chunk of the downloaded image. + The callback asset parameter will contain all previously received chunks of the texture asset starting + from the beginning of the request + + + + Sends the actual request packet to the simulator + + The image to download + Type of the image to download, either a baked + avatar texture or a normal texture + Priority level of the download. Default is + 1,013,000.0f + Number of quality layers to discard. + This controls the end marker of the data sent + Packet number to start the download at. + This controls the start marker of the data sent + Sending a priority of 0 and a discardlevel of -1 aborts + download + + + + Cancel a pending or in process texture request + + The texture assets unique ID + + + + Master Download Thread, Queues up downloads in the threadpool + + + + + The worker thread that sends the request and handles timeouts + + A object containing the request details + + + + Handle responses from the simulator that tell us a texture we have requested is unable to be located + or no longer exists. This will remove the request from the pipeline and free up a slot if one is in use + + The sender + The EventArgs object containing the packet data + + + + Handles the remaining Image data that did not fit in the initial ImageData packet + + The sender + The EventArgs object containing the packet data + + + + Handle the initial ImageDataPacket sent from the simulator + + The sender + The EventArgs object containing the packet data + + + + + + + + + Initialize the UDP packet handler in server mode + + Port to listening for incoming UDP packets on + + + + Initialize the UDP packet handler in client mode + + Remote UDP server to connect to + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Operation to apply when applying color to texture @@ -22584,6 +21656,14 @@ A unique ID + + The assets unique ID + + + + The "type" of asset, Notecard, Animation, etc + + Construct a new Asset object @@ -22609,24 +21689,11 @@ True if the asset decoding succeeded, otherwise false - - The assets unique ID - - - - The "type" of asset, Notecard, Animation, etc - - Constants for the archiving module - - - Path for region settings. - - The location of the archive control file @@ -22652,6 +21719,11 @@ Path for region settings. + + + Path for region settings. + + The character the separates the uuid from extension information in an archived asset filename @@ -22794,6 +21866,9 @@ Represents an Animation + + Override the base classes AssetType + Default Constructor @@ -22804,14 +21879,545 @@ A unique specific to this asset A byte array containing the raw asset data - - Override the base classes AssetType - Represents an that represents an avatars body ie: Hair, Etc. + + Override the base classes AssetType + + + Initializes a new instance of an AssetBodyPart object + + + Initializes a new instance of an AssetBodyPart object with parameters + A unique specific to this asset + A byte array containing the raw asset data + + + + Represents a Callingcard with AvatarID and Position vector + + + + Override the base classes AssetType + + + UUID of the Callingcard target avatar + + + Construct an Asset of type Callingcard + + + + Construct an Asset object of type Callingcard + + A unique specific to this asset + A byte array containing the raw asset data + + + + Constuct an asset of type Callingcard + + UUID of the target avatar + + + + Encode the raw contents of a string with the specific Callingcard format + + + + + Decode the raw asset data, populating the AvatarID and Position + + true if the AssetData was successfully decoded to a UUID and Vector + + + + Represents an that can be worn on an avatar + such as a Shirt, Pants, etc. + + + + Override the base classes AssetType + + + Initializes a new instance of an AssetScriptBinary object + + + Initializes a new instance of an AssetScriptBinary object with parameters + A unique specific to this asset + A byte array containing the raw asset data + + + + Type of gesture step + + + + + Base class for gesture steps + + + + + Retururns what kind of gesture step this is + + + + + Describes animation step of a gesture + + + + + Returns what kind of gesture step this is + + + + + If true, this step represents start of animation, otherwise animation stop + + + + + Animation asset + + + + + Animation inventory name + + + + + Describes sound step of a gesture + + + + + Returns what kind of gesture step this is + + + + + Sound asset + + + + + Sound inventory name + + + + + Describes sound step of a gesture + + + + + Returns what kind of gesture step this is + + + + + Text to output in chat + + + + + Describes sound step of a gesture + + + + + Returns what kind of gesture step this is + + + + + If true in this step we wait for all animations to finish + + + + + If true gesture player should wait for the specified amount of time + + + + + Time in seconds to wait if WaitForAnimation is false + + + + + Describes the final step of a gesture + + + + + Returns what kind of gesture step this is + + + + + Represents a sequence of animations, sounds, and chat actions + + + + + Returns asset type + + + + + Keyboard key that triggers the gestyre + + + + + Modifier to the trigger key + + + + + String that triggers playing of the gesture sequence + + + + + Text that replaces trigger in chat once gesture is triggered + + + + + Sequence of gesture steps + + + + + Constructs guesture asset + + + + + Constructs guesture asset + + A unique specific to this asset + A byte array containing the raw asset data + + + + Encodes gesture asset suitable for uplaod + + + + + Decodes gesture assset into play sequence + + true if the asset data was decoded successfully + + + + Represents a Landmark with RegionID and Position vector + + + + Override the base classes AssetType + + + UUID of the Landmark target region + + + Local position of the target + + + Construct an Asset of type Landmark + + + + Construct an Asset object of type Landmark + + A unique specific to this asset + A byte array containing the raw asset data + + + + Encode the raw contents of a string with the specific Landmark format + + + + + Decode the raw asset data, populating the RegionID and Position + + true if the AssetData was successfully decoded to a UUID and Vector + + + + Represents Mesh asset + + + + Override the base classes AssetType + + + + Decoded mesh data + + + + Initializes a new instance of an AssetMesh object + + + Initializes a new instance of an AssetMesh object with parameters + A unique specific to this asset + A byte array containing the raw asset data + + + + TODO: Encodes Collada file into LLMesh format + + + + + Decodes mesh asset. See + to furter decode it for rendering + true + + + + Represents an Animation + + + + Override the base classes AssetType + + + Default Constructor + + + + Construct an Asset object of type Animation + + Asset type + A unique specific to this asset + A byte array containing the raw asset data + + + + Represents a string of characters encoded with specific formatting properties + + + + Override the base classes AssetType + + + A text string containing main text of the notecard + + + List of s embedded on the notecard + + + Construct an Asset of type Notecard + + + + Construct an Asset object of type Notecard + + A unique specific to this asset + A byte array containing the raw asset data + + + + Encode the raw contents of a string with the specific Linden Text properties + + + + + Decode the raw asset data including the Linden Text properties + + true if the AssetData was successfully decoded + + + + A linkset asset, containing a parent primitive and zero or more children + + + + + Only used internally for XML serialization/deserialization + + + + Override the base classes AssetType + + + Initializes a new instance of an AssetPrim object + + + + Initializes a new instance of an AssetPrim object + + A unique specific to this asset + A byte array containing the raw asset data + + + + + + + + + + + + + + + The deserialized form of a single primitive in a linkset asset + + + + + Represents an AssetScriptBinary object containing the + LSO compiled bytecode of an LSL script + + + + Override the base classes AssetType + + + Initializes a new instance of an AssetScriptBinary object + + + Initializes a new instance of an AssetScriptBinary object with parameters + A unique specific to this asset + A byte array containing the raw asset data + + + + TODO: Encodes a scripts contents into a LSO Bytecode file + + + + + TODO: Decode LSO Bytecode into a string + + true + + + + Represents an LSL Text object containing a string of UTF encoded characters + + + + Override the base classes AssetType + + + A string of characters represting the script contents + + + Initializes a new AssetScriptText object + + + + Initializes a new AssetScriptText object with parameters + + A unique specific to this asset + A byte array containing the raw asset data + + + + Encode a string containing the scripts contents into byte encoded AssetData + + + + + Decode a byte array containing the scripts contents into a string + + true if decoding is successful + + + + Represents a Sound Asset + + + + Override the base classes AssetType + + + Initializes a new instance of an AssetSound object + + + Initializes a new instance of an AssetSound object with parameters + A unique specific to this asset + A byte array containing the raw asset data + + + + TODO: Encodes a sound file + + + + + TODO: Decode a sound file + + true + + + + Represents a texture + + + + Override the base classes AssetType + + + A object containing image data + + + + + + + + + Initializes a new instance of an AssetTexture object + + + + Initializes a new instance of an AssetTexture object + + A unique specific to this asset + A byte array containing the raw asset data + + + + Initializes a new instance of an AssetTexture object + + A object containing texture data + + + + Populates the byte array with a JPEG2000 + encoded image created from the data in + + + + + Decodes the JPEG2000 data in AssetData to the + object + + True if the decoding was successful, otherwise false + + + + Decodes the begin and end byte positions for each quality layer in + the image + + + Represents a Wearable Asset, Clothing, Hair, Skin, Etc @@ -22875,540 +22481,6 @@ Encode the assets string represantion into a format consumable by the asset server - - Initializes a new instance of an AssetBodyPart object - - - Initializes a new instance of an AssetBodyPart object with parameters - A unique specific to this asset - A byte array containing the raw asset data - - - Override the base classes AssetType - - - - Represents a Callingcard with AvatarID and Position vector - - - - UUID of the Callingcard target avatar - - - Construct an Asset of type Callingcard - - - - Construct an Asset object of type Callingcard - - A unique specific to this asset - A byte array containing the raw asset data - - - - Constuct an asset of type Callingcard - - UUID of the target avatar - - - - Encode the raw contents of a string with the specific Callingcard format - - - - - Decode the raw asset data, populating the AvatarID and Position - - true if the AssetData was successfully decoded to a UUID and Vector - - - Override the base classes AssetType - - - - Represents an that can be worn on an avatar - such as a Shirt, Pants, etc. - - - - Initializes a new instance of an AssetScriptBinary object - - - Initializes a new instance of an AssetScriptBinary object with parameters - A unique specific to this asset - A byte array containing the raw asset data - - - Override the base classes AssetType - - - - Type of gesture step - - - - - Base class for gesture steps - - - - - Retururns what kind of gesture step this is - - - - - Describes animation step of a gesture - - - - - If true, this step represents start of animation, otherwise animation stop - - - - - Animation asset - - - - - Animation inventory name - - - - - Returns what kind of gesture step this is - - - - - Describes sound step of a gesture - - - - - Sound asset - - - - - Sound inventory name - - - - - Returns what kind of gesture step this is - - - - - Describes sound step of a gesture - - - - - Text to output in chat - - - - - Returns what kind of gesture step this is - - - - - Describes sound step of a gesture - - - - - If true in this step we wait for all animations to finish - - - - - If true gesture player should wait for the specified amount of time - - - - - Time in seconds to wait if WaitForAnimation is false - - - - - Returns what kind of gesture step this is - - - - - Describes the final step of a gesture - - - - - Returns what kind of gesture step this is - - - - - Represents a sequence of animations, sounds, and chat actions - - - - - Keyboard key that triggers the gestyre - - - - - Modifier to the trigger key - - - - - String that triggers playing of the gesture sequence - - - - - Text that replaces trigger in chat once gesture is triggered - - - - - Sequence of gesture steps - - - - - Constructs guesture asset - - - - - Constructs guesture asset - - A unique specific to this asset - A byte array containing the raw asset data - - - - Encodes gesture asset suitable for uplaod - - - - - Decodes gesture assset into play sequence - - true if the asset data was decoded successfully - - - - Returns asset type - - - - - Represents a Landmark with RegionID and Position vector - - - - UUID of the Landmark target region - - - Local position of the target - - - Construct an Asset of type Landmark - - - - Construct an Asset object of type Landmark - - A unique specific to this asset - A byte array containing the raw asset data - - - - Encode the raw contents of a string with the specific Landmark format - - - - - Decode the raw asset data, populating the RegionID and Position - - true if the AssetData was successfully decoded to a UUID and Vector - - - Override the base classes AssetType - - - - Represents Mesh asset - - - - - Decoded mesh data - - - - Initializes a new instance of an AssetMesh object - - - Initializes a new instance of an AssetMesh object with parameters - A unique specific to this asset - A byte array containing the raw asset data - - - - TODO: Encodes Collada file into LLMesh format - - - - - Decodes mesh asset. See - to furter decode it for rendering - true - - - Override the base classes AssetType - - - - Represents an Animation - - - - Default Constructor - - - - Construct an Asset object of type Animation - - Asset type - A unique specific to this asset - A byte array containing the raw asset data - - - Override the base classes AssetType - - - - Represents a string of characters encoded with specific formatting properties - - - - A text string containing main text of the notecard - - - List of s embedded on the notecard - - - Construct an Asset of type Notecard - - - - Construct an Asset object of type Notecard - - A unique specific to this asset - A byte array containing the raw asset data - - - - Encode the raw contents of a string with the specific Linden Text properties - - - - - Decode the raw asset data including the Linden Text properties - - true if the AssetData was successfully decoded - - - Override the base classes AssetType - - - - A linkset asset, containing a parent primitive and zero or more children - - - - Initializes a new instance of an AssetPrim object - - - - Initializes a new instance of an AssetPrim object - - A unique specific to this asset - A byte array containing the raw asset data - - - - - - - - - - - - - - Override the base classes AssetType - - - - Only used internally for XML serialization/deserialization - - - - - The deserialized form of a single primitive in a linkset asset - - - - - Represents an AssetScriptBinary object containing the - LSO compiled bytecode of an LSL script - - - - Initializes a new instance of an AssetScriptBinary object - - - Initializes a new instance of an AssetScriptBinary object with parameters - A unique specific to this asset - A byte array containing the raw asset data - - - - TODO: Encodes a scripts contents into a LSO Bytecode file - - - - - TODO: Decode LSO Bytecode into a string - - true - - - Override the base classes AssetType - - - - Represents an LSL Text object containing a string of UTF encoded characters - - - - A string of characters represting the script contents - - - Initializes a new AssetScriptText object - - - - Initializes a new AssetScriptText object with parameters - - A unique specific to this asset - A byte array containing the raw asset data - - - - Encode a string containing the scripts contents into byte encoded AssetData - - - - - Decode a byte array containing the scripts contents into a string - - true if decoding is successful - - - Override the base classes AssetType - - - - Represents a Sound Asset - - - - Initializes a new instance of an AssetSound object - - - Initializes a new instance of an AssetSound object with parameters - A unique specific to this asset - A byte array containing the raw asset data - - - - TODO: Encodes a sound file - - - - - TODO: Decode a sound file - - true - - - Override the base classes AssetType - - - - Represents a texture - - - - A object containing image data - - - - - - - - - Initializes a new instance of an AssetTexture object - - - - Initializes a new instance of an AssetTexture object - - A unique specific to this asset - A byte array containing the raw asset data - - - - Initializes a new instance of an AssetTexture object - - A object containing texture data - - - - Populates the byte array with a JPEG2000 - encoded image created from the data in - - - - - Decodes the JPEG2000 data in AssetData to the - object - - True if the decoding was successful, otherwise false - - - - Decodes the begin and end byte positions for each quality layer in - the image - - - - - Override the base classes AssetType - = @@ -23424,6 +22496,24 @@ in to a single texture, for avatar appearances + + Final baked texture + + + Component layers + + + Width of the final baked image and scratchpad + + + Height of the final baked image and scratchpad + + + Bake type + + + Is this one of the 3 skin bakes + Final baked texture @@ -23486,24 +22576,6 @@ Green value Blue value - - Final baked texture - - - Component layers - - - Width of the final baked image and scratchpad - - - Height of the final baked image and scratchpad - - - Bake type - - - Is this one of the 3 skin bakes - Image width @@ -23593,6 +22665,32 @@ TGA Header size + + + Defines the beginning and ending file positions of a layer in an + LRCP-progression JPEG2000 file + + + + + This structure is used to marshal both encoded and decoded images. + MUST MATCH THE STRUCT IN dotnet.h! + + + + + Information about a single packet in a JPEG2000 stream + + + + Packet start position + + + Packet header end position + + + Packet end position + OpenJPEG is not threadsafe, so this object is used to lock during calls into unmanaged code @@ -23647,32 +22745,6 @@ true to enable lossless decoding A byte array containing the source Bitmap object - - - Defines the beginning and ending file positions of a layer in an - LRCP-progression JPEG2000 file - - - - - This structure is used to marshal both encoded and decoded images. - MUST MATCH THE STRUCT IN dotnet.h! - - - - - Information about a single packet in a JPEG2000 stream - - - - Packet start position - - - Packet header end position - - - Packet end position - Capability to load TGAs to Bitmap @@ -33471,6 +32543,12 @@ Use the same mesh used for geometry as the physical mesh upload + + + Callback for mesh upload operations + + null on failure, result from server on success + Creates instance of the mesh uploader @@ -33504,12 +32582,6 @@ Uri recieved in the upload prepare stage Callback that will be invoke upon completion of the upload. Null is sent on request failure - - - Callback for mesh upload operations - - null on failure, result from server on success - Interface requirements for Messaging system @@ -33567,6 +32639,347 @@ Face texture parameters Scale of the prim + + + Binary reader, which is endian aware + + + + What is the format of the source file + + + + Construct a reader from a stream + + The stream to read from + + + + Construct a reader from a stream + + The stream to read from + What is the format of the file, assumes PC and similar architecture + + + + Read a 32 bit integer + + A 32 bit integer in the system's endianness + + + + Read a 16 bit integer + + A 16 bit integer in the system's endianness + + + + Read a 64 bit integer + + A 64 bit integer in the system's endianness + + + + Read an unsigned 32 bit integer + + A 32 bit unsigned integer in the system's endianness + + + + Read a single precision floating point value + + A single precision floating point value in the system's endianness + + + + Read a double precision floating point value + + A double precision floating point value in the system's endianness + + + + Read a UTF-8 string + + A standard system string + + + + Read a UTF-8 string + + length of string to read + A standard system string + + + + Load and handle Linden Lab binary meshes. + + + The exact definition of this file is a bit sketchy, especially concerning skin weights. + A good starting point is on the + second life wiki + + + + + Defines a polygon + + + + + Structure of a vertex, No surprises there, except for the Detail tex coord + + + The skinweights are a tad unconventional. The best explanation found is: + >Each weight actually contains two pieces of information. The number to the + >left of the decimal point is the index of the joint and also implicitly + >indexes to the following joint. The actual weight is to the right of the + >decimal point and interpolates between these two joints. The index is into + >an "expanded" list of joints, not just a linear array of the joints as + >defined in the skeleton file. In particular, any joint that has more than + >one child will be repeated in the list for each of its children. + + Maybe I'm dense, but that description seems to be a bit hard to build an + algorithm on. + + Esentially the weights are compressed into one floating point value. + 1. The whole number part is an index into an array of joints + 2. The fractional part is the weight that joint has + 3. If the fractional part is 0 (x.0000) then the vertex is 100% influenced by the specified joint + + + + + Provide a nice format for debugging + + Vertex definition as a string + + + + Describes deltas to apply to a vertex in order to morph a vertex + + + + + Provide a nice format for debugging + + MorphVertex definition as a string + + + + Describes a named mesh morph, essentially a named list of MorphVertices + + + + + Provide a nice format for debugging + + The name of the morph + + + + Don't really know what this does + + + + + Provide a nice format for debugging + + Human friendly format + + + + A reference mesh is one way to implement level of detail + + + Reference meshes are supplemental meshes to full meshes. For all practical + purposes almost all lod meshes are implemented as reference meshes, except for + 'avatar_eye_1.llm' which for some reason is implemented as a full mesh. + + + + + Load a mesh from a stream + + Filename and path of the file containing the reference mesh + + + + Level of Detail mesh + + + + + Construct a linden mesh with the given name + + the name of the mesh + + + + Construct a linden mesh with the given name + + the name of the mesh + The skeleton governing mesh deformation + + + + Load the mesh from a stream + + The filename and path of the file containing the mesh data + + + + Layout of one skinweight element + + + + List of skinweights, in the same order as the mesh vertices + + + + Decompress the skinweights + + the expanded joint list, used to index which bones should influece the vertex + + + + Load a reference mesh from a given stream + + The lod level of this reference mesh + the name and path of the file containing the mesh data + the loaded reference mesh + + + + Trim a string at the first occurence of NUL + + + The llm file uses null terminated strings (C/C++ style), this is where + the conversion is made. + + The string to trim + A standard .Net string + + + + load the 'avatar_skeleton.xml' + + + Partial class which extends the auto-generated 'LindenSkeleton.Xsd.cs'.eton.xsd + + + + + + Load a skeleton from a given file. + + + We use xml scema validation on top of the xml de-serializer, since the schema has + some stricter checks than the de-serializer provides. E.g. the vector attributes + are guaranteed to hold only 3 float values. This reduces the need for error checking + while working with the loaded skeleton. + + A valid recursive skeleton + + + + Load a skeleton from a given file. + + + We use xml scema validation on top of the xml de-serializer, since the schema has + some stricter checks than the de-serializer provides. E.g. the vector attributes + are guaranteed to hold only 3 float values. This reduces the need for error checking + while working with the loaded skeleton. + + The path to the skeleton definition file + A valid recursive skeleton + + + + Build and "expanded" list of joints + + + The algorithm is based on this description: + + >An "expanded" list of joints, not just a + >linear array of the joints as defined in the skeleton file. + >In particular, any joint that has more than one child will + >be repeated in the list for each of its children. + + The list should only take these joint names in consideration + An "expanded" joints list as a flat list of bone names + + + + Expand one joint + + The parent of the joint we are operating on + The joint we are supposed to expand + Joint list that we will extend upon + The expanded list should only contain these joints + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Contains all mesh faces that belong to a prim + + + + List of primitive faces + + + + Decodes mesh asset into FacetedMesh + + Mesh primitive + Asset retrieved from the asset server + Level of detail + Resulting decoded FacetedMesh + True if mesh asset decoding was successful + Sent to the client to indicate a teleport request has completed @@ -33706,21 +33119,6 @@ the DataBlocksExtended map will not be sent from the simulator - - An Array of objects - - - - Serialize the object - - An containing the objects data - - - - Deserialize the message - - An containing the data - Prim ownership information for a specified owner on a single parcel @@ -33743,6 +33141,21 @@ The date the most recent prim was rezzed + + An Array of objects + + + + Serialize the object + + An containing the objects data + + + + Deserialize the message + + An containing the data + The details of a single parcel in a region, also contains some regionwide globals @@ -34171,26 +33584,6 @@ The Agent receiving the message - - An array containing information - for each the agent is a member of - - - An array containing information - for each the agent is a member of - - - - Serialize the object - - An containing the objects data - - - - Deserialize the message - - An containing the data - Group Details specific to the agent @@ -34220,6 +33613,26 @@ true of the agent allows this group to be listed in their profile + + An array containing information + for each the agent is a member of + + + An array containing information + for each the agent is a member of + + + + Serialize the object + + An containing the objects data + + + + Deserialize the message + + An containing the data + A message sent from the viewer to the simulator which @@ -34253,6 +33666,15 @@ leaves a group + + An object containing the Agents UUID, and the Groups UUID + + + The ID of the Agent leaving the group + + + The GroupID the Agent is leaving + An Array containing the AgentID and GroupID @@ -34270,15 +33692,6 @@ An containing the data - - An object containing the Agents UUID, and the Groups UUID - - - The ID of the Agent leaving the group - - - The GroupID the Agent is leaving - Base class for Asset uploads/results via Capabilities @@ -34738,21 +34151,6 @@ A message sent from the simulator to the viewer which contains an array of map images and their grid coordinates - - An array containing LayerData items - - - - Serialize the object - - An containing the objects data - - - - Deserialize the message - - An containing the data - An object containing map location details @@ -34773,6 +34171,21 @@ The grid location of the northern border of the map tile + + An array containing LayerData items + + + + Serialize the object + + An containing the objects data + + + + Deserialize the message + + An containing the data + Object containing request or response @@ -35147,10 +34560,54 @@ - Deseializes the message + Deserializes the message Incoming data to deserialize + + + Deserializes the message + + Incoming data to deserialize + + + + Serializes the message + + Serialized OSD + + + + + Deserializes the message + + Incoming data to deserialize + + + + Serializes the message + + Serialized OSD + + + + Deserializes the message + + Incoming data to deserialize + + + + Serializes the message + + Serialized OSD + + + + Detects which class handles deserialization of this message + + An containing the data + Object capable of decoding this message + A message sent from the viewer to the simulator which @@ -35630,6 +35087,941 @@ Serialized OSD data Deserialized object + + + Particle system specific enumerators, flags and methods. + + + + + Current version of the media data for the prim + + + + + Array of media entries indexed by face number + + + + + Complete structure for the particle system + + + + + Particle source pattern + + + + None + + + Drop particles from source position with no force + + + "Explode" particles in all directions + + + Particles shoot across a 2D area + + + Particles shoot across a 3D Cone + + + Inverse of AngleCone (shoot particles everywhere except the 3D cone defined + + + + Particle Data Flags + + + + None + + + Interpolate color and alpha from start to end + + + Interpolate scale from start to end + + + Bounce particles off particle sources Z height + + + velocity of particles is dampened toward the simulators wind + + + Particles follow the source + + + Particles point towards the direction of source's velocity + + + Target of the particles + + + Particles are sent in a straight line + + + Particles emit a glow + + + used for point/grab/touch + + + continuous ribbon particle + + + particle data contains glow + + + particle data contains blend functions + + + + Particle Flags Enum + + + + None + + + Acceleration and velocity for particles are + relative to the object rotation + + + Particles use new 'correct' angle parameters + + + Particle Flags + There appears to be more data packed in to this area + for many particle systems. It doesn't appear to be flag values + and serialization breaks unless there is a flag for every + possible bit so it is left as an unsigned integer + + + pattern of particles + + + A representing the maximimum age (in seconds) particle will be displayed + Maximum value is 30 seconds + + + A representing the number of seconds, + from when the particle source comes into view, + or the particle system's creation, that the object will emits particles; + after this time period no more particles are emitted + + + A in radians that specifies where particles will not be created + + + A in radians that specifies where particles will be created + + + A representing the number of seconds between burts. + + + A representing the number of meters + around the center of the source where particles will be created. + + + A representing in seconds, the minimum speed between bursts of new particles + being emitted + + + A representing in seconds the maximum speed of new particles being emitted. + + + A representing the maximum number of particles emitted per burst + + + A which represents the velocity (speed) from the source which particles are emitted + + + A which represents the Acceleration from the source which particles are emitted + + + The Key of the texture displayed on the particle + + + The Key of the specified target object or avatar particles will follow + + + Flags of particle from + + + Max Age particle system will emit particles for + + + The the particle has at the beginning of its lifecycle + + + The the particle has at the ending of its lifecycle + + + A that represents the starting X size of the particle + Minimum value is 0, maximum value is 4 + + + A that represents the starting Y size of the particle + Minimum value is 0, maximum value is 4 + + + A that represents the ending X size of the particle + Minimum value is 0, maximum value is 4 + + + A that represents the ending Y size of the particle + Minimum value is 0, maximum value is 4 + + + A that represents the start glow value + Minimum value is 0, maximum value is 1 + + + A that represents the end glow value + Minimum value is 0, maximum value is 1 + + + OpenGL blend function to use at particle source + + + OpenGL blend function to use at particle destination + + + + Can this particle system be packed in a legacy compatible way + + True if the particle system doesn't use new particle system features + + + + Decodes a byte[] array into a ParticleSystem Object + + ParticleSystem object + Start position for BitPacker + + + + Generate byte[] array from particle data + + Byte array + + + + + + + Parameters used to construct a visual representation of a primitive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Attachment point to an avatar + + + + + + + + + + + + + + + + Calculdates hash code for prim construction data + + The has + + + + Information on the flexible properties of a primitive + + + + + + + + + + + + + + + + + + + + + + + Default constructor + + + + + + + + + + + + + + + + + + + + + + + + Information on the light properties of a primitive + + + + + + + + + + + + + + + + + + + + Default constructor + + + + + + + + + + + + + + + + + + + + + + + + Information on the light properties of a primitive as texture map + + + + + + + + + + + Default constructor + + + + + + + + + + + + + + + + + + + + + + + + Information on the sculpt properties of a sculpted primitive + + + + + Render inside out (inverts the normals). + + + + + Render an X axis mirror of the sculpty. + + + + + Default constructor + + + + + + + + + + + + Extended properties to describe an object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default constructor + + + + + Set the properties that are set in an ObjectPropertiesFamily packet + + that has + been partially filled by an ObjectPropertiesFamily packet + + + + Describes physics attributes of the prim + + + + Primitive's local ID + + + Density (1000 for normal density) + + + Friction + + + Gravity multiplier (1 for normal gravity) + + + Type of physics representation of this primitive in the simulator + + + Restitution + + + + Creates PhysicsProperties from OSD + + OSDMap with incoming data + Deserialized PhysicsProperties object + + + + Serializes PhysicsProperties to OSD + + OSDMap with serialized PhysicsProperties data + + + + + + + + + + + + + + + + + + + + + Foliage type for this primitive. Only applicable if this + primitive is foliage + + + Unknown + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Identifies the owner if audio or a particle system is + active + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Objects physics engine propertis + + + Extra data about primitive + + + Indicates if prim is attached to an avatar + + + Number of clients referencing this prim + + + Uses basic heuristics to estimate the primitive shape + + + + Default constructor + + + + + Packs PathTwist, PathTwistBegin, PathRadiusOffset, and PathSkew + parameters in to signed eight bit values + + Floating point parameter to pack + Signed eight bit value containing the packed parameter + + + + Unpacks PathTwist, PathTwistBegin, PathRadiusOffset, and PathSkew + parameters from signed eight bit integers to floating point values + + Signed eight bit value to unpack + Unpacked floating point value + + + + Texture animation mode + + + + Disable texture animation + + + Enable texture animation + + + Loop when animating textures + + + Animate in reverse direction + + + Animate forward then reverse + + + Slide texture smoothly instead of frame-stepping + + + Rotate texture instead of using frames + + + Scale texture instead of using frames + + + + A single textured face. Don't instantiate this class yourself, use the + methods in TextureEntry + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + In the future this will specify whether a webpage is + attached to this face + + + + + + + + + + Contains the definition for individual faces + + + + + + + + + + + + Represents all of the texturable faces for an object + + Grid objects have infinite faces, with each face + using the properties of the default face unless set otherwise. So if + you have a TextureEntry with a default texture uuid of X, and face 18 + has a texture UUID of Y, every face would be textured with X except for + face 18 that uses Y. In practice however, primitives utilize a maximum + of nine faces + + + + + + + + + + Constructor that takes a default texture UUID + + Texture UUID to use as the default texture + + + + Constructor that takes a TextureEntryFace for the + default face + + Face to use as the default face + + + + Constructor that creates the TextureEntry class from a byte array + + Byte array containing the TextureEntry field + Starting position of the TextureEntry field in + the byte array + Length of the TextureEntry field, in bytes + + + + This will either create a new face if a custom face for the given + index is not defined, or return the custom face for that index if + it already exists + + The index number of the face to create or + retrieve + A TextureEntryFace containing all the properties for that + face + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Controls the texture animation of a particular prim + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The type of bump-mapping applied to a face @@ -35768,29 +36160,6 @@ - - - Level of Detail mesh - - - - - Contains all mesh faces that belong to a prim - - - - List of primitive faces - - - - Decodes mesh asset into FacetedMesh - - Mesh primitive - Asset retrieved from the asset server - Level of detail - Resulting decoded FacetedMesh - True if mesh asset decoding was successful - This is used to login a specific user account(s). It may only be called after @@ -35930,6 +36299,16 @@ The level of the audio, a number between -100 and 100 where 0 represents ‘normal’ speaking volume + + + List of audio input devices + + + + + List of audio output devices + + Start up the Voice service. @@ -36003,6 +36382,11 @@ Handle response to audio input device query + + + Set audio test mode + + Set voice channel for new parcel @@ -36035,6 +36419,60 @@ + + Enable logging + + + The folder where any logs will be created + + + This will be prepended to beginning of each log file + + + The suffix or extension to be appended to each log file + + + + 0: NONE - No logging + 1: ERROR - Log errors only + 2: WARNING - Log errors and warnings + 3: INFO - Log errors, warnings and info + 4: DEBUG - Log errors, warnings, info and debug + + + + + Constructor for default logging settings + + + + Audio Properties Events are sent after audio capture is started. These events are used to display a microphone VU meter + + + + Event for most mundane request reposnses. + + + + Response to Connector.Create request + + + Response to Aux.GetCaptureDevices request + + + Response to Aux.GetRenderDevices request + + + Audio Properties Events are sent after audio capture is started. + These events are used to display a microphone VU meter + + + Response to Account.Login request + + + This event message is sent whenever the login state of the + particular Account has transitioned from one value to another + Starts a thread that keeps the daemon running @@ -36128,75 +36566,6 @@ The level of the audio, a number between -100 and 100 where 0 represents ‘normal’ speaking volume - - - List of audio input devices - - - - - List of audio output devices - - - - - Set audio test mode - - - - - Event for most mundane request reposnses. - - - - Response to Connector.Create request - - - Response to Aux.GetCaptureDevices request - - - Response to Aux.GetRenderDevices request - - - Audio Properties Events are sent after audio capture is started. - These events are used to display a microphone VU meter - - - Response to Account.Login request - - - This event message is sent whenever the login state of the - particular Account has transitioned from one value to another - - - Enable logging - - - The folder where any logs will be created - - - This will be prepended to beginning of each log file - - - The suffix or extension to be appended to each log file - - - - 0: NONE - No logging - 1: ERROR - Log errors only - 2: WARNING - Log errors and warnings - 3: INFO - Log errors, warnings and info - 4: DEBUG - Log errors, warnings, info and debug - - - - - Constructor for default logging settings - - - - Audio Properties Events are sent after audio capture is started. These events are used to display a microphone VU meter - Positional vector of the users position @@ -36236,5 +36605,52 @@ + + + + + + + + Delegate to wrap another delegate and its arguments + + + + + + + An instance of DelegateWrapper which calls InvokeWrappedDelegate, + which in turn calls the DynamicInvoke method of the wrapped + delegate + + + + + Callback used to call EndInvoke on the asynchronously + invoked DelegateWrapper + + + + + Executes the specified delegate with the specified arguments + asynchronously on a thread pool thread + + + + + + + Invokes the wrapped delegate synchronously + + + + + + + Calls EndInvoke on the wrapper and Close on the resulting WaitHandle + to prevent resource leaks + + + diff --git a/bin/OpenMetaverse.dll b/bin/OpenMetaverse.dll index 7a1bc0b42535c2e50c7588fd85e5755ceb66d3dc..5c576a7a6f5e3b46285b8078abf1aa12abdcb82d 100755 GIT binary patch literal 2199552 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

;@;MF|} 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%0ADT* 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%0Dt?CER1T@yA!-~2z=(#^ooi52_T_<@K1pHJ- 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%0DDIO}8OnhbYn_}a#$0-$yHWtnv9dFQ1>IyDDQ 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

VYzK}-D-c*~i>|E+mdL#3u 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 phCZAJd0|}GQtJ$b=$?jWq=hY&J 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
  • C%Rt6FOB=ar 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ℜ}QRjE^2NQzeJZb{lx#E%bMH8uh11ufAMSd4f+;c)!ZR| zhrZVg5C!d>VuIEyUZ?emU682tixScxtu`R)kX{=UuSZ?AA@K&(Oh)T3I;$3KvcC1*6 z%Cr%2Fe*nw&`|9-ahP_zSfQODR-!6xtvFnJzc>Qjt(_>2ME7Xx#8K#8G#dQ`Rcq_T z`%qZhAdW#b+D36KifAW^#M$TxGzUG2=4u}opF;Drv&ElkpAhG3=ZH_E1==UYpP_}?x#Bb0r^H3*S?xS= zF?vq>Q*nuQzW8&rRQt5}3$#qTKztr8M=xl9Cayp)Y8Q$t(J!^nh^x>`+C}1O^egSN z;u`d_cCok?{aX8+xDLIdT_UbWuWElTZa}}$E)_ST-=a<0Ux=@v&Dv$+>u8JidGU8> zt9H5g2HK{5L3|T!*RBxX(!MC}K)**jwJXIxpk3NuihtCu5_h9NXIQ;x8f=EPwgi0H2N5w(Y_}B3!T+&7C%Afw6BYwqVw7< z;%Ddr`ds@v@eA~C?N;$3`cnIbcnSSSyG^`|zCu^DZ;D@|Z?xORZ_!olTjF=WVXcR;)qCFyC>K z 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�*tVMDds**Zk#Leq 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 BET#Ye literal 2195456 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 +?uUDgQ$-ThGg&Rq!q04P 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%0A_&L=8Oi#68aas+}=TvZ0vf#0m;?C#nV^i{M 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�Gk^~0Bm6(0kEZk1i)4X5&&BpNC0eO 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

  • - Collection of textures and parameters that can be - worn by an avatar + Collection of textures and parameters that can be worn by an avatar Primitive that can contain textures, sounds, @@ -263,10 +262,7 @@ Notecard asset - Holds a collection of inventory items - - - Root inventory folder + Holds a collection of inventory items. "Category" in the Linden viewer Linden scripting language script @@ -278,17 +274,7 @@ Uncompressed TGA texture - Collection of textures and shape parameters that can - be worn - - - Trash folder - - - Snapshot folder - - - Lost and found folder + Collection of textures and shape parameters that can be worn Uncompressed sound @@ -310,44 +296,109 @@ Simstate file - - Contains landmarks for favorites - Asset is a link to another inventory item Asset is a link to another inventory folder - - Beginning of the range reserved for ensembles - - - End of the range reserved for ensembles - - - Folder containing inventory links to wearables and attachments - that are part of the current outfit - - - Folder containing inventory items or links to - inventory items of wearables and attachments - together make a full outfit - - - Root folder for the folders of type OutfitFolder + + Marketplace Folder. Same as an Category but different display methods. Linden mesh format - + + + The different types of folder. + + + + None folder type + + + Texture folder type + + + Sound folder type + + + Calling card folder type + + + Landmark folder type + + + Clothing folder type + + + Object folder type + + + Notecard folder type + + + The root folder type + + + LSLText folder + + + Bodyparts folder + + + Trash folder + + + Snapshot folder + + + Lost And Found folder + + + Animation folder + + + Gesture folder + + + Favorites folder + + + Ensemble beginning range + + + Ensemble ending range + + + Current outfit folder + + + Outfit folder + + + My outfits folder + + + Mesh folder + + Marketplace direct delivery inbox ("Received Items") - + Marketplace direct delivery outbox - - + + Basic root folder + + + Marketplace listings folder + + + Marketplace stock folder + + + Hypergrid Suitcase folder @@ -1071,38 +1122,6 @@ multiple writers - - Queue head - - - Queue tail - - - Queue item count - - - - Constructor - - - - - Enqueue an item - - Item to enqeue - - - - Try to dequeue an item - - Dequeued item if the dequeue was successful - True if an item was successfully deqeued, otherwise false - - - Gets the current number of items in the queue. Since this - is a lockless collection this value should be treated as a close - estimate - Provides a node container for data in a singly linked list @@ -1124,6 +1143,38 @@ Constructor + + Queue head + + + Queue tail + + + Queue item count + + + Gets the current number of items in the queue. Since this + is a lockless collection this value should be treated as a close + estimate + + + + Constructor + + + + + Enqueue an item + + Item to enqeue + + + + Try to dequeue an item + + Dequeued item if the dequeue was successful + True if an item was successfully deqeued, otherwise false + Convert this matrix to euler rotations @@ -1334,6 +1385,37 @@ Time of the last drip, in system ticks + + + The parent bucket of this bucket, or null if this bucket has no + parent. The parent bucket will limit the aggregate bandwidth of all + of its children buckets + + + + + Maximum burst rate in bytes per second. This is the maximum number + of tokens that can accumulate in the bucket at any one time + + + + + The speed limit of this bucket in bytes per second. This is the + number of tokens that are added to the bucket per second + + Tokens are added to the bucket any time + is called, at the granularity of + the system tick interval (typically around 15-22ms) + + + + The number of bytes that can be sent at this moment. This is the + current number of tokens in the bucket + If this bucket has a parent bucket that does not have + enough tokens for a request, will + return false regardless of the content of this bucket + + Default constructor @@ -1371,36 +1453,36 @@ True if tokens were added to the bucket, otherwise false - + - The parent bucket of this bucket, or null if this bucket has no - parent. The parent bucket will limit the aggregate bandwidth of all - of its children buckets + Operating system - + + Unknown + + + Microsoft Windows + + + Microsoft Windows CE + + + Linux + + + Apple OSX + + - Maximum burst rate in bytes per second. This is the maximum number - of tokens that can accumulate in the bucket at any one time + Runtime platform - - - The speed limit of this bucket in bytes per second. This is the - number of tokens that are added to the bucket per second - - Tokens are added to the bucket any time - is called, at the granularity of - the system tick interval (typically around 15-22ms) + + .NET runtime - - - The number of bytes that can be sent at this moment. This is the - current number of tokens in the bucket - If this bucket has a parent bucket that does not have - enough tokens for a request, will - return false regardless of the content of this bucket - + + Mono runtime: http://www.mono-project.com/ Used for converting degrees to radians @@ -1842,6 +1924,20 @@ A string containing the AssetType name The AssetType which matches the string name, or AssetType.Unknown if no match was found + + + Takes a FolderType and returns the string representation + + The source + The string version of the FolderType + + + + Translate a string name of an FolderType into the proper Type + + A string containing the FolderType name + The FolderType which matches the string name, or FolderType. None if no match was found + Convert an InventoryType to a string @@ -1972,37 +2068,6 @@ Converted IP address object, or null if the conversion failed - - - Operating system - - - - Unknown - - - Microsoft Windows - - - Microsoft Windows CE - - - Linux - - - Apple OSX - - - - Runtime platform - - - - .NET runtime - - - Mono runtime: http://www.mono-project.com/ - A 128-bit Universally Unique Identifier, used throughout the Second diff --git a/bin/OpenMetaverseTypes.dll b/bin/OpenMetaverseTypes.dll index dd1ea6c6539acfe1aecd705e7b2eaed3db2e6e9e..a07cc1daa01e7c46f90c83f8a2242858edbcc767 100755 GIT binary patch delta 16680 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From f03a6bbc616c3c9ce8dadce6059cf7899ef91b9b Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Mon, 2 Jan 2017 17:47:20 +0000 Subject: [PATCH 236/305] Create a generic way for passing constructor args to plugins The old syntax didn't allow for any parameters except for services listed in the ServiceList. Now, services loaded by other services can also be made to use different ini sections or have additional paramters. Syntax is: [@]...[:] --- OpenSim/Server/Base/ServerUtils.cs | 12 ++++++++++++ .../Inventory/XInventoryServicesConnector.cs | 12 ++++++++++-- OpenSim/Services/LLLoginService/LLLoginService.cs | 9 +++++++-- bin/Robust.HG.ini.example | 5 +++-- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs index 18a426676e..57d0a8d56c 100644 --- a/OpenSim/Server/Base/ServerUtils.cs +++ b/OpenSim/Server/Base/ServerUtils.cs @@ -242,6 +242,18 @@ namespace OpenSim.Server.Base className = parts[2]; } + // Handle extra string arguments in a more generic way + if (dllName.Contains("@")) + { + string[] dllNameParts = dllName.Split(new char[] {'@'}); + dllName = dllNameParts[dllNameParts.Length - 1]; + List argList = new List(args); + for (int i = 0 ; i < dllNameParts.Length - 1 ; ++i) + argList.Add(dllNameParts[i]); + + args = argList.ToArray(); + } + return LoadPlugin(dllName, className, args); } diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs index 2ddd7a2f55..bd5841bef1 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs @@ -63,6 +63,7 @@ namespace OpenSim.Services.Connectors /// In this case, -1 is default timeout (100 seconds), not infinite. /// private int m_requestTimeoutSecs = -1; + private string m_configName = "InventoryService"; private const double CACHE_EXPIRATION_SECONDS = 20.0; private static ExpiringCache m_ItemCache = new ExpiringCache(); @@ -76,6 +77,13 @@ namespace OpenSim.Services.Connectors m_ServerURI = serverURI.TrimEnd('/'); } + public XInventoryServicesConnector(IConfigSource source, string configName) + : base(source, configName) + { + m_configName = configName; + Initialise(source); + } + public XInventoryServicesConnector(IConfigSource source) : base(source, "InventoryService") { @@ -84,10 +92,10 @@ namespace OpenSim.Services.Connectors public virtual void Initialise(IConfigSource source) { - IConfig config = source.Configs["InventoryService"]; + IConfig config = source.Configs[m_configName]; if (config == null) { - m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); + m_log.ErrorFormat("[INVENTORY CONNECTOR]: {0} missing from OpenSim.ini", m_configName); throw new Exception("Inventory connector init error"); } diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 6d63959a2a..5d69705f79 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -180,9 +180,14 @@ namespace OpenSim.Services.LLLoginService string hgInvServicePlugin = m_LoginServerConfig.GetString("HGInventoryServicePlugin", String.Empty); if (hgInvServicePlugin != string.Empty) { + // TODO: Remove HGInventoryServiceConstructorArg after 0.9 release string hgInvServiceArg = m_LoginServerConfig.GetString("HGInventoryServiceConstructorArg", String.Empty); - Object[] args2 = new Object[] { config, hgInvServiceArg }; - m_HGInventoryService = ServerUtils.LoadPlugin(hgInvServicePlugin, args2); + if (hgInvServiceArg != String.Empty) + { + m_log.Warn("[LLOGIN SERVICE]: You are using HGInventoryServiceConstructorArg, which is deprecated. See example file for correct syntax."); + hgInvServicePlugin = hgInvServiceArg + "@" + hgInvServicePlugin; + } + m_HGInventoryService = ServerUtils.LoadPlugin(hgInvServicePlugin, args); } // diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index 20c080475e..7d13d4382f 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -488,8 +488,9 @@ UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" ; This inventory service will be used to initialize the user's inventory - HGInventoryServicePlugin = "OpenSim.Services.HypergridService.dll:HGSuitcaseInventoryService" - HGInventoryServiceConstructorArg = "HGInventoryService" + HGInventoryServicePlugin = "HGInventoryService@OpenSim.Services.HypergridService.dll:HGSuitcaseInventoryService" + ; NOTE: HGInventoryServiceConstructorArg is deprecated. For now it will work, but see above + ; for the correct method if passing additional arguments. ;; end hypergrid ; Ask co-operative viewers to use a different currency name From 966e50d90c9ef9b5fde9830b6b0e90290eb2ea47 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Mon, 2 Jan 2017 19:30:40 +0000 Subject: [PATCH 237/305] Add the HGRemoteAssetService. Allows to use any asset service with HG --- .../HypergridService/HGRemoteAssetService.cs | 240 ++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 OpenSim/Services/HypergridService/HGRemoteAssetService.cs diff --git a/OpenSim/Services/HypergridService/HGRemoteAssetService.cs b/OpenSim/Services/HypergridService/HGRemoteAssetService.cs new file mode 100644 index 0000000000..a53435beeb --- /dev/null +++ b/OpenSim/Services/HypergridService/HGRemoteAssetService.cs @@ -0,0 +1,240 @@ +/* + * 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.IO; +using System.Reflection; +using System.Xml; + +using Nini.Config; +using log4net; +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Serialization.External; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Services.AssetService; + +namespace OpenSim.Services.HypergridService +{ + /// + /// Hypergrid asset service. It serves the IAssetService interface, + /// but implements it in ways that are appropriate for inter-grid + /// asset exchanges. + /// + public class HGRemoteAssetService : IAssetService + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private string m_HomeURL; + private IUserAccountService m_UserAccountService; + private IAssetService m_assetConnector; + + private UserAccountCache m_Cache; + + private AssetPermissions m_AssetPerms; + + public HGRemoteAssetService(IConfigSource config, string configName) + { + m_log.Debug("[HGRemoteAsset Service]: Starting"); + IConfig assetConfig = config.Configs[configName]; + if (assetConfig == null) + throw new Exception("No HGAssetService configuration"); + + Object[] args = new Object[] { config }; + + string assetConnectorDll = assetConfig.GetString("AssetConnector", String.Empty); + if (assetConnectorDll == String.Empty) + throw new Exception("Please specify AssetConnector in HGAssetService configuration"); + + m_assetConnector = ServerUtils.LoadPlugin(assetConnectorDll, args); + if (m_assetConnector == null) + throw new Exception(String.Format("Unable to create AssetConnector from {0}", assetConnectorDll)); + + string userAccountsDll = assetConfig.GetString("UserAccountsService", string.Empty); + if (userAccountsDll == string.Empty) + throw new Exception("Please specify UserAccountsService in HGAssetService configuration"); + + m_UserAccountService = ServerUtils.LoadPlugin(userAccountsDll, args); + if (m_UserAccountService == null) + throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll)); + + m_HomeURL = Util.GetConfigVarFromSections(config, "HomeURI", + new string[] { "Startup", "Hypergrid", configName }, string.Empty); + if (m_HomeURL == string.Empty) + throw new Exception("[HGAssetService] No HomeURI specified"); + + m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); + + // Permissions + m_AssetPerms = new AssetPermissions(assetConfig); + + } + + #region IAssetService overrides + public AssetBase Get(string id) + { + AssetBase asset = m_assetConnector.Get(id); + + if (asset == null) + return null; + + if (!m_AssetPerms.AllowedExport(asset.Type)) + return null; + + if (asset.Metadata.Type == (sbyte)AssetType.Object) + asset.Data = AdjustIdentifiers(asset.Data); + + AdjustIdentifiers(asset.Metadata); + + return asset; + } + + public AssetMetadata GetMetadata(string id) + { + AssetMetadata meta = m_assetConnector.GetMetadata(id); + + if (meta == null) + return null; + + AdjustIdentifiers(meta); + + return meta; + } + + public byte[] GetData(string id) + { + AssetBase asset = Get(id); + + if (asset == null) + return null; + + if (!m_AssetPerms.AllowedExport(asset.Type)) + return null; + + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before sending them elsewhere + if (asset.Type == (int)AssetType.Object && asset.Data != null) + { + string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data)); + asset.Data = Utils.StringToBytes(xml); + } + + return asset.Data; + } + + // public delegate void AssetRetrieved(string id, Object sender, AssetBase asset); + public virtual bool Get(string id, Object sender, AssetRetrieved handler) + { + return m_assetConnector.Get(id, sender, (i, s, asset) => + { + if (asset != null) + { + if (!m_AssetPerms.AllowedExport(asset.Type)) + { + asset = null; + } + else + { + if (asset.Metadata.Type == (sbyte)AssetType.Object) + asset.Data = AdjustIdentifiers(asset.Data); + + AdjustIdentifiers(asset.Metadata); + } + } + + handler(i, s, asset); + }); + } + + public string Store(AssetBase asset) + { + if (!m_AssetPerms.AllowedImport(asset.Type)) + return string.Empty; + + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before storing on this server + if (asset.Type == (int)AssetType.Object && asset.Data != null) + { + string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data)); + asset.Data = Utils.StringToBytes(xml); + } + + return m_assetConnector.Store(asset); + } + + public bool Delete(string id) + { + // NOGO + return false; + } + + #endregion + + protected void AdjustIdentifiers(AssetMetadata meta) + { + if (meta == null || m_Cache == null) + return; + + UserAccount creator = m_Cache.GetUser(meta.CreatorID); + if (creator != null) + meta.CreatorID = meta.CreatorID + ";" + m_HomeURL + "/" + creator.FirstName + " " + creator.LastName; + } + + // Only for Object + protected byte[] AdjustIdentifiers(byte[] data) + { + string xml = Utils.BytesToString(data); + + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before sending them elsewhere + xml = ExternalRepresentationUtils.SanitizeXml(xml); + + return Utils.StringToBytes(ExternalRepresentationUtils.RewriteSOP(xml, "HGAssetService", m_HomeURL, m_Cache, UUID.Zero)); + } + + public AssetBase GetCached(string id) + { + return Get(id); + } + + public bool[] AssetsExist(string[] ids) + { + return m_assetConnector.AssetsExist(ids); + } + + public bool UpdateContent(string id, byte[] data) + { + // SO not happening!! + return false; + } + } + +} From 504a69906b1ced5691128174fcebabc6d433294a Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Tue, 3 Jan 2017 14:05:37 +0000 Subject: [PATCH 238/305] Suppress error messages in the log if functions are not enabled. Just return failure instead. --- .../Handlers/UserAccounts/UserAccountServerPostHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs b/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs index b22c4cc6fd..a02255f01d 100644 --- a/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs +++ b/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs @@ -98,7 +98,7 @@ namespace OpenSim.Server.Handlers.UserAccounts if (m_AllowCreateUser) return CreateUser(request); else - break; + return FailureResult(); case "getaccount": return GetAccount(request); case "getaccounts": @@ -109,7 +109,7 @@ namespace OpenSim.Server.Handlers.UserAccounts if (m_AllowSetAccount) return StoreAccount(request); else - break; + return FailureResult(); } m_log.DebugFormat("[USER SERVICE HANDLER]: unknown method request: {0}", method); From 995242b351a5460bbb6358f490a6679f7e660b42 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Tue, 3 Jan 2017 18:31:17 +0000 Subject: [PATCH 239/305] Suppress misleading message when logging in locally The gatekeeper and travel info address will not actually be set there, stop OpenSim from showing a blank address. It's confusing. --- OpenSim/Services/HypergridService/UserAgentService.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs index 317d0066b3..e701ec6a81 100644 --- a/OpenSim/Services/HypergridService/UserAgentService.cs +++ b/OpenSim/Services/HypergridService/UserAgentService.cs @@ -301,8 +301,12 @@ namespace OpenSim.Services.HypergridService // Everything is ok - // Update the perceived IP Address of our grid - m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP); + if (!fromLogin) + { + // Update the perceived IP Address of our grid + m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP); + } + travel.MyIpAddress = myExternalIP; StoreTravelInfo(travel); From b0db5752202f8e8e56390ac0c062b9f500575290 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Wed, 4 Jan 2017 19:13:59 +0000 Subject: [PATCH 240/305] Set a sensible default for the MaxAgentGroups parameter MaxAgentGroups is in the [Groups] section, but is read by the login service. If the login service and the groups service don't share the same ini file, that will be sent to the viewer as zero and groups will not work. --- OpenSim/Services/LLLoginService/LLLoginService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 5d69705f79..80fc56fd8e 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -82,7 +82,7 @@ namespace OpenSim.Services.LLLoginService protected string m_SearchURL; protected string m_Currency; protected string m_ClassifiedFee; - protected int m_MaxAgentGroups; + protected int m_MaxAgentGroups = 42; protected string m_DestinationGuide; protected string m_AvatarPicker; protected string m_AllowedClients; From ed641b22b3c840cd133b71e069cb93cd4dce1d7d Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Wed, 4 Jan 2017 20:06:41 +0100 Subject: [PATCH 241/305] Show details of scene objects with given ownerId. Signed-off-by: Mandarinka Tasty Signed-off-by: Melanie Thielker --- .../Objects/Commands/ObjectCommandsModule.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs index 688648b965..e53ab95351 100644 --- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs @@ -149,6 +149,15 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands + "If --regex is specified then the name is treatead as a regular expression.", HandleShowObjectByName); + m_console.Commands.AddCommand( + "Objects", + false, + "show object owner", + "show object owner [--full] ", + "Show details of scene objects with given owner.", + "The --full option will print out information on all the parts of the object.\n", + HandleShowObjectByOwnerID); + m_console.Commands.AddCommand( "Objects", false, @@ -325,6 +334,32 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands OutputSogsToConsole(searchPredicate, showFull); } + private void HandleShowObjectByOwnerID(string module, string[] cmdparams) + { + if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) + return; + + bool showFull = false; + OptionSet options = new OptionSet().Add("full", v => showFull = v != null); + + List mainParams = options.Parse(cmdparams); + + if (mainParams.Count < 4) + { + m_console.OutputFormat("Usage: show object owner "); + return; + } + + UUID ownerID; + if (!ConsoleUtil.TryParseConsoleUuid(m_console, mainParams[3], out ownerID)) + return; + + Predicate searchPredicate + = so => so.OwnerID == ownerID && !so.IsAttachment; + + OutputSogsToConsole(searchPredicate, showFull); + } + private void HandleShowObjectByPos(string module, string[] cmdparams) { if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) From af93822465d8d873b94f536e6e6d8ee5f7f9fdea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geir=20N=C3=B8klebye?= Date: Wed, 4 Jan 2017 21:32:09 +0100 Subject: [PATCH 242/305] PGSQL fixed a missing cast to uuid in XInventoryData Signed-off-by: Melanie Thielker --- OpenSim/Data/PGSQL/PGSQLXInventoryData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs b/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs index c34a8dce87..959c2cf393 100644 --- a/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs +++ b/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs @@ -205,7 +205,7 @@ namespace OpenSim.Data.PGSQL */ cmd.CommandText = String.Format(@"select bit_or(""inventoryCurrentPermissions"") as ""inventoryCurrentPermissions"" from inventoryitems - where ""avatarID"" = :PrincipalID + where ""avatarID""::uuid = :PrincipalID and ""assetID"" = :AssetID group by ""assetID"" "); From af1b00db419d21d629cd1d5cd0ec4e06060d310f Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Sun, 1 Jan 2017 21:36:40 +0100 Subject: [PATCH 243/305] The robust command login reset should return config value: MinLoginLevel. Defaultly, it returns 0. Signed-off-by: Mandarinka Tasty Signed-off-by: Melanie Thielker --- OpenSim/Services/LLLoginService/LLLoginService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 80fc56fd8e..2941f51be1 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -1066,8 +1066,8 @@ namespace OpenSim.Services.LLLoginService } break; - case "reset": - m_MinLoginLevel = 0; + case "reset": + m_MinLoginLevel = m_LoginServerConfig.GetInt("MinLoginLevel", 0); MainConsole.Instance.OutputFormat("Reset min login level to {0}", m_MinLoginLevel); break; From 53fe204eed63aec8c3217a63bafe5f462a21dba3 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 5 Jan 2017 13:35:13 +0000 Subject: [PATCH 244/305] Create all tables ad InnoDB by default MyISAM isn't properly replicated using row based replication. With the advances in clustering, these systems are becoming more prevalent and MyISAM isn't up to the task anymore. --- OpenSim/Data/MySQL/Resources/IM_Store.migrations | 2 +- .../Data/MySQL/Resources/RegionStore.migrations | 16 ++++++++-------- .../Data/MySQL/Resources/UserProfiles.migrations | 10 +++++----- .../MySQL/Resources/os_groups_Store.migrations | 16 ++++++++-------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/OpenSim/Data/MySQL/Resources/IM_Store.migrations b/OpenSim/Data/MySQL/Resources/IM_Store.migrations index e271fcc20f..4f148267ba 100644 --- a/OpenSim/Data/MySQL/Resources/IM_Store.migrations +++ b/OpenSim/Data/MySQL/Resources/IM_Store.migrations @@ -11,6 +11,6 @@ CREATE TABLE IF NOT EXISTS `im_offline` ( PRIMARY KEY (`ID`), KEY `PrincipalID` (`PrincipalID`), KEY `FromID` (`FromID`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; COMMIT; diff --git a/OpenSim/Data/MySQL/Resources/RegionStore.migrations b/OpenSim/Data/MySQL/Resources/RegionStore.migrations index 2108c764b3..c63cc95d22 100644 --- a/OpenSim/Data/MySQL/Resources/RegionStore.migrations +++ b/OpenSim/Data/MySQL/Resources/RegionStore.migrations @@ -97,7 +97,7 @@ CREATE TABLE IF NOT EXISTS `prims` ( PRIMARY KEY (`UUID`), KEY `prims_regionuuid` (`RegionUUID`), KEY `prims_scenegroupid` (`SceneGroupID`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `primshapes` ( `Shape` int(11) DEFAULT NULL, @@ -130,7 +130,7 @@ CREATE TABLE IF NOT EXISTS `primshapes` ( `Media` text, `LastAttachPoint` int(4) NOT NULL DEFAULT '0', PRIMARY KEY (`UUID`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `primitems` ( `invType` int(11) DEFAULT NULL, @@ -154,13 +154,13 @@ CREATE TABLE IF NOT EXISTS `primitems` ( `lastOwnerID` char(36) DEFAULT NULL, PRIMARY KEY (`itemID`), KEY `primitems_primid` (`primID`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `terrain` ( `RegionUUID` varchar(255) DEFAULT NULL, `Revision` int(11) DEFAULT NULL, `Heightfield` longblob -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `land` ( `UUID` varchar(255) NOT NULL, @@ -204,21 +204,21 @@ CREATE TABLE IF NOT EXISTS `land` ( `ObscureMusic` tinyint(1) NOT NULL DEFAULT '0', `ObscureMedia` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`UUID`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `landaccesslist` ( `LandUUID` varchar(255) DEFAULT NULL, `AccessUUID` varchar(255) DEFAULT NULL, `Flags` int(11) DEFAULT NULL, `Expires` int(11) NOT NULL DEFAULT '0' -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `regionban` ( `regionUUID` varchar(36) NOT NULL, `bannedUUID` varchar(36) NOT NULL, `bannedIp` varchar(16) NOT NULL, `bannedIpHostMask` varchar(16) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `regionsettings` ( `regionUUID` char(36) NOT NULL, @@ -265,7 +265,7 @@ CREATE TABLE IF NOT EXISTS `regionsettings` ( `parcel_tile_ID` char(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', `covenant_datetime` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`regionUUID`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `regionwindlight` ( `region_id` varchar(36) NOT NULL DEFAULT '000000-0000-0000-0000-000000000000', diff --git a/OpenSim/Data/MySQL/Resources/UserProfiles.migrations b/OpenSim/Data/MySQL/Resources/UserProfiles.migrations index 008e455031..cfcc18b477 100644 --- a/OpenSim/Data/MySQL/Resources/UserProfiles.migrations +++ b/OpenSim/Data/MySQL/Resources/UserProfiles.migrations @@ -27,7 +27,7 @@ CREATE TABLE IF NOT EXISTS `usernotes` ( `targetuuid` varchar(36) NOT NULL, `notes` text NOT NULL, UNIQUE KEY `useruuid` (`useruuid`,`targetuuid`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `userpicks` ( @@ -46,7 +46,7 @@ CREATE TABLE IF NOT EXISTS `userpicks` ( `enabled` enum('true','false') NOT NULL, `gatekeeper` varchar(255), PRIMARY KEY (`pickuuid`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `userprofile` ( @@ -65,7 +65,7 @@ CREATE TABLE IF NOT EXISTS `userprofile` ( `profileFirstImage` varchar(36) NOT NULL, `profileFirstText` text NOT NULL, PRIMARY KEY (`useruuid`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `userdata` ( `UserId` char(36) NOT NULL, @@ -73,7 +73,7 @@ CREATE TABLE IF NOT EXISTS `userdata` ( `DataKey` varchar(255), `DataVal` varchar(255), PRIMARY KEY (`UserId`,`TagId`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `usersettings` ( `useruuid` varchar(36) NOT NULL, @@ -81,6 +81,6 @@ CREATE TABLE IF NOT EXISTS `usersettings` ( `visible` enum('true','false') NOT NULL, `email` varchar(254) NOT NULL, PRIMARY KEY (`useruuid`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; +) ENGINE=InnoDB DEFAULT CHARSET=latin1; commit; diff --git a/OpenSim/Data/MySQL/Resources/os_groups_Store.migrations b/OpenSim/Data/MySQL/Resources/os_groups_Store.migrations index 9e6f1c112c..1a499000fb 100644 --- a/OpenSim/Data/MySQL/Resources/os_groups_Store.migrations +++ b/OpenSim/Data/MySQL/Resources/os_groups_Store.migrations @@ -18,7 +18,7 @@ CREATE TABLE `os_groups_groups` ( PRIMARY KEY (`GroupID`), UNIQUE KEY `Name` (`Name`), FULLTEXT KEY `Name_2` (`Name`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE TABLE `os_groups_membership` ( @@ -31,7 +31,7 @@ CREATE TABLE `os_groups_membership` ( `AccessToken` char(36) NOT NULL default '', PRIMARY KEY (`GroupID`,`PrincipalID`), KEY `PrincipalID` (`PrincipalID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE TABLE `os_groups_roles` ( @@ -43,7 +43,7 @@ CREATE TABLE `os_groups_roles` ( `Powers` bigint(20) unsigned NOT NULL default '0', PRIMARY KEY (`GroupID`,`RoleID`), KEY `GroupID` (`GroupID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE TABLE `os_groups_rolemembership` ( @@ -52,7 +52,7 @@ CREATE TABLE `os_groups_rolemembership` ( `PrincipalID` VARCHAR(255) NOT NULL default '', PRIMARY KEY (`GroupID`,`RoleID`,`PrincipalID`), KEY `PrincipalID` (`PrincipalID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE TABLE `os_groups_invites` ( @@ -63,7 +63,7 @@ CREATE TABLE `os_groups_invites` ( `TMStamp` timestamp NOT NULL, PRIMARY KEY (`InviteID`), UNIQUE KEY `PrincipalGroup` (`GroupID`,`PrincipalID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE TABLE `os_groups_notices` ( @@ -81,13 +81,13 @@ CREATE TABLE `os_groups_notices` ( PRIMARY KEY (`NoticeID`), KEY `GroupID` (`GroupID`), KEY `TMStamp` (`TMStamp`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE TABLE `os_groups_principals` ( `PrincipalID` VARCHAR(255) NOT NULL default '', `ActiveGroupID` char(36) NOT NULL default '', PRIMARY KEY (`PrincipalID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; COMMIT; @@ -112,4 +112,4 @@ DROP TABLE `diva_groups_principals`; DELETE FROM `migrations` WHERE name='diva_im_Store'; -COMMIT; \ No newline at end of file +COMMIT; From f4a51116f63ac9641f3df254fbf8001c771903df Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 5 Jan 2017 14:17:00 +0000 Subject: [PATCH 245/305] Fix some permissions checks in groups The code checked the permissions of a person being added to a role rather than those of the person doing the adding. Also, limited permission role removal wasn't implemented. --- .../Addons/Groups/Service/GroupsService.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs index ae0518cc8a..710b00a43e 100644 --- a/OpenSim/Addons/Groups/Service/GroupsService.cs +++ b/OpenSim/Addons/Groups/Service/GroupsService.cs @@ -496,7 +496,7 @@ namespace OpenSim.Groups if (!unlimited && limited) { // check whether person's has this role - RoleMembershipData rolemembership = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID); + RoleMembershipData rolemembership = m_Database.RetrieveRoleMember(GroupID, RoleID, RequestingAgentID); if (rolemembership == null) { m_log.DebugFormat("[Groups]: ({0}) Attempt at assigning {1} to role {2} denied because of limited permission", RequestingAgentID, AgentID, RoleID); @@ -516,13 +516,26 @@ namespace OpenSim.Groups return false; // check permissions + bool limited = HasPower(RequestingAgentID, GroupID, GroupPowers.AssignMemberLimited); bool unlimited = HasPower(RequestingAgentID, GroupID, GroupPowers.AssignMember) || IsOwner(RequestingAgentID, GroupID); - if (!unlimited) + if (!limited && !unlimited) { m_log.DebugFormat("[Groups]: ({0}) Attempt at removing {1} from role {2} denied because of lack of permission", RequestingAgentID, AgentID, RoleID); return false; } + // AssignMemberLimited means that the person can assign another person to the same roles that she has in the group + if (!unlimited && limited) + { + // check whether person's has this role + RoleMembershipData rolemembership = m_Database.RetrieveRoleMember(GroupID, RoleID, RequestingAgentID); + if (rolemembership == null) + { + m_log.DebugFormat("[Groups]: ({0}) Attempt at removing {1} from role {2} denied because of limited permission", RequestingAgentID, AgentID, RoleID); + return false; + } + } + RoleMembershipData rolemember = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID); if (rolemember == null) @@ -812,7 +825,7 @@ namespace OpenSim.Groups if (RoleID != UUID.Zero) _AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); - // Make thit this active group + // Make this the active group PrincipalData pdata = new PrincipalData(); pdata.PrincipalID = AgentID; pdata.ActiveGroupID = GroupID; From d43a3bec19314ecb0610e1600de88c98ac186f17 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 5 Jan 2017 16:27:17 +0000 Subject: [PATCH 246/305] a few changes to estates and estate teleportHome (used kick) --- .../World/Estate/EstateManagementModule.cs | 18 +++++- .../World/Estate/XEstateConnector.cs | 56 +++++++++++-------- .../CoreModules/World/Estate/XEstateModule.cs | 36 +++++------- .../World/Estate/XEstateRequestHandler.cs | 13 ++++- .../Framework/Interfaces/IEstateModule.cs | 2 + 5 files changed, 78 insertions(+), 47 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 8eb2b1eb37..efd4ca6bad 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -71,6 +71,8 @@ namespace OpenSim.Region.CoreModules.World.Estate public event ChangeDelegate OnRegionInfoChange; public event ChangeDelegate OnEstateInfoChange; public event MessageDelegate OnEstateMessage; + public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; + public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; private int m_delayCount = 0; @@ -1193,13 +1195,20 @@ namespace OpenSim.Region.CoreModules.World.Estate private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID, UUID prey) { + EstateTeleportOneUserHomeRequest evOverride = OnEstateTeleportOneUserHomeRequest; + if(evOverride != null) + { + evOverride(remover_client, invoice, senderID, prey); + return; + } + if (!Scene.Permissions.CanIssueEstateCommand(remover_client.AgentId, false)) return; if (prey != UUID.Zero) { ScenePresence s = Scene.GetScenePresence(prey); - if (s != null) + if (s != null && !s.IsDeleted && !s.IsInTransit) { if (!Scene.TeleportClientHome(prey, s.ControllingClient)) { @@ -1212,6 +1221,13 @@ namespace OpenSim.Region.CoreModules.World.Estate private void handleEstateTeleportAllUsersHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID) { + EstateTeleportAllUsersHomeRequest evOverride = OnEstateTeleportAllUsersHomeRequest; + if(evOverride != null) + { + evOverride(remover_client, invoice, senderID); + return; + } + if (!Scene.Permissions.CanIssueEstateCommand(remover_client.AgentId, false)) return; diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs index 73e706c339..2c0c882b60 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs @@ -46,16 +46,19 @@ namespace OpenSim.Region.CoreModules.World.Estate private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected XEstateModule m_EstateModule; + private string token; - public EstateConnector(XEstateModule module) + public EstateConnector(XEstateModule module, string _token) { m_EstateModule = module; + token = _token; } public void SendTeleportHomeOneUser(uint EstateID, UUID PreyID) { Dictionary sendData = new Dictionary(); sendData["METHOD"] = "teleport_home_one_user"; + sendData["TOKEN"] = token; sendData["EstateID"] = EstateID.ToString(); sendData["PreyID"] = PreyID.ToString(); @@ -67,6 +70,7 @@ namespace OpenSim.Region.CoreModules.World.Estate { Dictionary sendData = new Dictionary(); sendData["METHOD"] = "teleport_home_all_users"; + sendData["TOKEN"] = token; sendData["EstateID"] = EstateID.ToString(); @@ -77,6 +81,7 @@ namespace OpenSim.Region.CoreModules.World.Estate { Dictionary sendData = new Dictionary(); sendData["METHOD"] = "update_covenant"; + sendData["TOKEN"] = token; sendData["CovenantID"] = CovenantID.ToString(); sendData["EstateID"] = EstateID.ToString(); @@ -99,6 +104,7 @@ namespace OpenSim.Region.CoreModules.World.Estate { Dictionary sendData = new Dictionary(); sendData["METHOD"] = "update_estate"; + sendData["TOKEN"] = token; sendData["EstateID"] = EstateID.ToString(); @@ -119,6 +125,7 @@ namespace OpenSim.Region.CoreModules.World.Estate { Dictionary sendData = new Dictionary(); sendData["METHOD"] = "estate_message"; + sendData["TOKEN"] = token; sendData["EstateID"] = EstateID.ToString(); sendData["FromID"] = FromID.ToString(); @@ -132,47 +139,43 @@ namespace OpenSim.Region.CoreModules.World.Estate { List regions = m_EstateModule.Scenes[0].GetEstateRegions((int)EstateID); - UUID ScopeID = UUID.Zero; + // Don't send to the same instance twice + List done = new List(); // Handle local regions locally - // lock (m_EstateModule.Scenes) { foreach (Scene s in m_EstateModule.Scenes) { - if (regions.Contains(s.RegionInfo.RegionID)) + RegionInfo sreg = s.RegionInfo; + if (regions.Contains(sreg.RegionID)) { - // All regions in one estate are in the same scope. - // Use that scope. - // - ScopeID = s.RegionInfo.ScopeID; - regions.Remove(s.RegionInfo.RegionID); + string url = sreg.ExternalHostName + ":" + sreg.HttpPort; + regions.Remove(sreg.RegionID); + if(!done.Contains(url)) // we may have older regs with same url lost in dbs + done.Add(url); } } } - // Our own region should always be in the above list. - // In a standalone this would not be true. But then, - // Scope ID is not relevat there. Use first scope. - // - if (ScopeID == UUID.Zero) - ScopeID = m_EstateModule.Scenes[0].RegionInfo.ScopeID; + if(regions.Count == 0) + return; - // Don't send to the same instance twice - // - List done = new List(); + Scene baseScene = m_EstateModule.Scenes[0]; + UUID ScopeID = baseScene.RegionInfo.ScopeID; + IGridService gridService = baseScene.GridService; + if(gridService == null) + return; // Send to remote regions - // foreach (UUID regionID in regions) { - GridRegion region = m_EstateModule.Scenes[0].GridService.GetRegionByUUID(ScopeID, regionID); + GridRegion region = gridService.GetRegionByUUID(ScopeID, regionID); if (region != null) { - string url = "http://" + region.ExternalHostName + ":" + region.HttpPort; - if (done.Contains(url)) + string url = region.ExternalHostName + ":" + region.HttpPort; + if(done.Contains(url)) continue; - Call(region, sendData); done.Add(url); } @@ -185,7 +188,12 @@ namespace OpenSim.Region.CoreModules.World.Estate // m_log.DebugFormat("[XESTATE CONNECTOR]: queryString = {0}", reqString); try { - string url = "http://" + region.ExternalHostName + ":" + region.HttpPort; + string url = ""; + if(string.IsNullOrEmpty(region.ServerURI)) + url = "http://" + region.ExternalHostName + ":" + region.HttpPort; + else + url = region.ServerURI; + string reply = SynchronousRestFormsRequester.MakeRequest("POST", url + "/estate", reqString); diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs index 4bb3799dc9..a7195af2a5 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs @@ -51,6 +51,7 @@ namespace OpenSim.Region.CoreModules.World.Estate protected List m_Scenes = new List(); protected bool m_InInfoUpdate = false; + private string token = "7db8eh2gvgg45jj"; public bool InInfoUpdate { @@ -69,17 +70,19 @@ namespace OpenSim.Region.CoreModules.World.Estate { int port = 0; - IConfig estateConfig = config.Configs["Estate"]; + IConfig estateConfig = config.Configs["Estates"]; if (estateConfig != null) { port = estateConfig.GetInt("Port", 0); + // this will need to came from somewhere else + token = estateConfig.GetString("Token", token); } - m_EstateConnector = new EstateConnector(this); + m_EstateConnector = new EstateConnector(this, token); // Instantiate the request handler IHttpServer server = MainServer.GetHttpServer((uint)port); - server.AddStreamHandler(new EstateRequestHandler(this)); + server.AddStreamHandler(new EstateRequestHandler(this, token)); } public void PostInitialise() @@ -94,8 +97,6 @@ namespace OpenSim.Region.CoreModules.World.Estate { lock (m_Scenes) m_Scenes.Add(scene); - - scene.EventManager.OnNewClient += OnNewClient; } public void RegionLoaded(Scene scene) @@ -105,12 +106,12 @@ namespace OpenSim.Region.CoreModules.World.Estate em.OnRegionInfoChange += OnRegionInfoChange; em.OnEstateInfoChange += OnEstateInfoChange; em.OnEstateMessage += OnEstateMessage; + em.OnEstateTeleportOneUserHomeRequest += OnEstateTeleportOneUserHomeRequest; + em.OnEstateTeleportAllUsersHomeRequest += OnEstateTeleportAllUsersHomeRequest; } public void RemoveRegion(Scene scene) { - scene.EventManager.OnNewClient -= OnNewClient; - lock (m_Scenes) m_Scenes.Remove(scene); } @@ -181,13 +182,6 @@ namespace OpenSim.Region.CoreModules.World.Estate m_EstateConnector.SendEstateMessage(estateID, FromID, FromName, Message); } - private void OnNewClient(IClientAPI client) - { - client.OnEstateTeleportOneUserHomeRequest += OnEstateTeleportOneUserHomeRequest; - client.OnEstateTeleportAllUsersHomeRequest += OnEstateTeleportAllUsersHomeRequest; - - } - private void OnEstateTeleportOneUserHomeRequest(IClientAPI client, UUID invoice, UUID senderID, UUID prey) { if (prey == UUID.Zero) @@ -205,16 +199,18 @@ namespace OpenSim.Region.CoreModules.World.Estate foreach (Scene s in Scenes) { - if (s == scene) - continue; // Already handles by estate module if (s.RegionInfo.EstateSettings.EstateID != estateID) continue; ScenePresence p = scene.GetScenePresence(prey); - if (p != null && !p.IsChildAgent) + if (p != null && !p.IsChildAgent ) { - p.ControllingClient.SendTeleportStart(16); - scene.TeleportClientHome(prey, p.ControllingClient); + if(!p.IsDeleted && !p.IsInTransit) + { + p.ControllingClient.SendTeleportStart(16); + scene.TeleportClientHome(prey, p.ControllingClient); + } + return; } } @@ -235,8 +231,6 @@ namespace OpenSim.Region.CoreModules.World.Estate foreach (Scene s in Scenes) { - if (s == scene) - continue; // Already handles by estate module if (s.RegionInfo.EstateSettings.EstateID != estateID) continue; diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs index 1dcaed333f..756b54dcb1 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs @@ -48,11 +48,13 @@ namespace OpenSim.Region.CoreModules.World.Estate protected XEstateModule m_EstateModule; protected Object m_RequestLock = new Object(); + private string token; - public EstateRequestHandler(XEstateModule fmodule) + public EstateRequestHandler(XEstateModule fmodule, string _token) : base("POST", "/estate") { m_EstateModule = fmodule; + token = _token; } protected override byte[] ProcessRequest(string path, Stream requestData, @@ -75,6 +77,15 @@ namespace OpenSim.Region.CoreModules.World.Estate if (!request.ContainsKey("METHOD")) return FailureResult(); + if (!request.ContainsKey("TOKEN")) + return FailureResult(); + + string reqToken = request["TOKEN"].ToString(); + request.Remove("TOKEN"); + + if(token != reqToken) + return FailureResult(); + string method = request["METHOD"].ToString(); request.Remove("METHOD"); diff --git a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs index 461c880fe0..6b8b999ae2 100644 --- a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs @@ -39,6 +39,8 @@ namespace OpenSim.Region.Framework.Interfaces event ChangeDelegate OnRegionInfoChange; event ChangeDelegate OnEstateInfoChange; event MessageDelegate OnEstateMessage; + event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; + event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; uint GetRegionFlags(); bool IsManager(UUID avatarID); From 40e982f6e7c3b2fbfa8aaa78615f98b431648880 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 5 Jan 2017 17:11:03 +0000 Subject: [PATCH 247/305] a few changes to estates port handling --- .../CoreModules/World/Estate/XEstateConnector.cs | 8 +++++--- .../Region/CoreModules/World/Estate/XEstateModule.cs | 11 +++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs index 2c0c882b60..e56bd951da 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs @@ -47,11 +47,13 @@ namespace OpenSim.Region.CoreModules.World.Estate protected XEstateModule m_EstateModule; private string token; + uint port = 0; - public EstateConnector(XEstateModule module, string _token) + public EstateConnector(XEstateModule module, string _token, uint _port) { m_EstateModule = module; token = _token; + port = _port; } public void SendTeleportHomeOneUser(uint EstateID, UUID PreyID) @@ -189,8 +191,8 @@ namespace OpenSim.Region.CoreModules.World.Estate try { string url = ""; - if(string.IsNullOrEmpty(region.ServerURI)) - url = "http://" + region.ExternalHostName + ":" + region.HttpPort; + if(port != 0) + url = "http://" + region.ExternalHostName + ":" + port; else url = region.ServerURI; diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs index a7195af2a5..f9438fe31b 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs @@ -68,20 +68,23 @@ namespace OpenSim.Region.CoreModules.World.Estate public void Initialise(IConfigSource config) { - int port = 0; + uint port = MainServer.Instance.Port; IConfig estateConfig = config.Configs["Estates"]; if (estateConfig != null) { - port = estateConfig.GetInt("Port", 0); + port = (uint)estateConfig.GetInt("Port", 0); // this will need to came from somewhere else token = estateConfig.GetString("Token", token); } - m_EstateConnector = new EstateConnector(this, token); + m_EstateConnector = new EstateConnector(this, token, port); + + if(port == 0) + port = MainServer.Instance.Port; // Instantiate the request handler - IHttpServer server = MainServer.GetHttpServer((uint)port); + IHttpServer server = MainServer.GetHttpServer(port); server.AddStreamHandler(new EstateRequestHandler(this, token)); } From e0a6691932244c57acbcfc94bae240db0772ea51 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 5 Jan 2017 17:59:21 +0000 Subject: [PATCH 248/305] Rename the files and classes from XEstate to Estate The names conflict with it's ancestor module and the code is nothing like the out of core XEstateModule, so it should not be named the same. --- .../World/Estate/{XEstateConnector.cs => EstateConnector.cs} | 4 ++-- .../World/Estate/{XEstateModule.cs => EstateModule.cs} | 2 +- .../{XEstateRequestHandler.cs => EstateRequestHandler.cs} | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename OpenSim/Region/CoreModules/World/Estate/{XEstateConnector.cs => EstateConnector.cs} (98%) rename OpenSim/Region/CoreModules/World/Estate/{XEstateModule.cs => EstateModule.cs} (99%) rename OpenSim/Region/CoreModules/World/Estate/{XEstateRequestHandler.cs => EstateRequestHandler.cs} (98%) diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/EstateConnector.cs similarity index 98% rename from OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs rename to OpenSim/Region/CoreModules/World/Estate/EstateConnector.cs index e56bd951da..ad561fd8ef 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateConnector.cs @@ -45,11 +45,11 @@ namespace OpenSim.Region.CoreModules.World.Estate { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - protected XEstateModule m_EstateModule; + protected EstateModule m_EstateModule; private string token; uint port = 0; - public EstateConnector(XEstateModule module, string _token, uint _port) + public EstateConnector(EstateModule module, string _token, uint _port) { m_EstateModule = module; token = _token; diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs similarity index 99% rename from OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs rename to OpenSim/Region/CoreModules/World/Estate/EstateModule.cs index f9438fe31b..8eb38c2aa8 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs @@ -45,7 +45,7 @@ using Mono.Addins; namespace OpenSim.Region.CoreModules.World.Estate { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEstate")] - public class XEstateModule : ISharedRegionModule + public class EstateModule : ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs b/OpenSim/Region/CoreModules/World/Estate/EstateRequestHandler.cs similarity index 98% rename from OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs rename to OpenSim/Region/CoreModules/World/Estate/EstateRequestHandler.cs index 756b54dcb1..7ab92d1a47 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateRequestHandler.cs @@ -46,11 +46,11 @@ namespace OpenSim.Region.CoreModules.World.Estate { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - protected XEstateModule m_EstateModule; + protected EstateModule m_EstateModule; protected Object m_RequestLock = new Object(); private string token; - public EstateRequestHandler(XEstateModule fmodule, string _token) + public EstateRequestHandler(EstateModule fmodule, string _token) : base("POST", "/estate") { m_EstateModule = fmodule; From cbc3501246d5250788634f6d1b6fbd1f60661c85 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 5 Jan 2017 18:02:59 +0000 Subject: [PATCH 249/305] a few changes to Gods ( ie administrators) control --- OpenSim/Framework/IClientAPI.cs | 4 +- .../ClientStack/Linden/UDP/LLClientView.cs | 48 ++++--- .../CoreModules/Avatar/Gods/GodsModule.cs | 125 ++++++++---------- .../Framework/Interfaces/IGodsModule.cs | 5 +- .../Region/Framework/Scenes/ScenePresence.cs | 36 ++--- 5 files changed, 99 insertions(+), 119 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index c4de81e93a..1541b3a3dc 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -227,10 +227,10 @@ namespace OpenSim.Framework byte RayEndIsIntersection); public delegate void RequestGodlikePowers( - UUID AgentID, UUID SessionID, UUID token, bool GodLike, IClientAPI remote_client); + UUID AgentID, UUID SessionID, UUID token, bool GodLike); public delegate void GodKickUser( - UUID GodAgentID, UUID GodSessionID, UUID AgentID, uint kickflags, byte[] reason); + UUID GodAgentID, UUID AgentID, uint kickflags, byte[] reason); public delegate void CreateInventoryFolder( IClientAPI remoteClient, UUID folderID, ushort folderType, string folderName, UUID parentID); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 55050d9de4..27ca74043b 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -10455,6 +10455,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP private bool HandleRequestGodlikePowers(IClientAPI sender, Packet Pack) { RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack; + + if (rglpPack.AgentData.SessionID != SessionId || + rglpPack.AgentData.AgentID != AgentId) + return true; + RequestGodlikePowersPacket.RequestBlockBlock rblock = rglpPack.RequestBlock; UUID token = rblock.Token; @@ -10464,7 +10469,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (handlerReqGodlikePowers != null) { - handlerReqGodlikePowers(ablock.AgentID, ablock.SessionID, token, rblock.Godlike, this); + handlerReqGodlikePowers(ablock.AgentID, ablock.SessionID, token, rblock.Godlike); } return true; @@ -10475,6 +10480,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP GodUpdateRegionInfoPacket GodUpdateRegionInfo = (GodUpdateRegionInfoPacket)Packet; + if (GodUpdateRegionInfo.AgentData.SessionID != SessionId || + GodUpdateRegionInfo.AgentData.AgentID != AgentId) + return true; + GodUpdateRegionInfoUpdate handlerGodUpdateRegionInfo = OnGodUpdateRegionInfoUpdate; if (handlerGodUpdateRegionInfo != null) { @@ -10508,6 +10517,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP GodlikeMessagePacket GodlikeMessage = (GodlikeMessagePacket)Packet; + if (GodlikeMessage.AgentData.SessionID != SessionId || + GodlikeMessage.AgentData.AgentID != AgentId) + return true; + GodlikeMessage handlerGodlikeMessage = onGodlikeMessage; if (handlerGodlikeMessage != null) { @@ -10524,6 +10537,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP { StateSavePacket SaveStateMessage = (StateSavePacket)Packet; + + if (SaveStateMessage.AgentData.SessionID != SessionId || + SaveStateMessage.AgentData.AgentID != AgentId) + return true; + SaveStateHandler handlerSaveStatePacket = OnSaveState; if (handlerSaveStatePacket != null) { @@ -10537,30 +10555,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP { GodKickUserPacket gkupack = (GodKickUserPacket)Pack; - if (gkupack.UserInfo.GodSessionID == SessionId && AgentId == gkupack.UserInfo.GodID) + if (gkupack.UserInfo.GodSessionID != SessionId || + gkupack.UserInfo.GodID != AgentId) + return true; + + GodKickUser handlerGodKickUser = OnGodKickUser; + if (handlerGodKickUser != null) { - GodKickUser handlerGodKickUser = OnGodKickUser; - if (handlerGodKickUser != null) - { - handlerGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.GodSessionID, - gkupack.UserInfo.AgentID, gkupack.UserInfo.KickFlags, gkupack.UserInfo.Reason); - } + handlerGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.AgentID, gkupack.UserInfo.KickFlags, gkupack.UserInfo.Reason); } - else - { - SendAgentAlertMessage("Kick request denied", false); - } - //KickUserPacket kupack = new KickUserPacket(); - //KickUserPacket.UserInfoBlock kupackib = kupack.UserInfo; - //kupack.UserInfo.AgentID = gkupack.UserInfo.AgentID; - //kupack.UserInfo.SessionID = gkupack.UserInfo.GodSessionID; - - //kupack.TargetBlock.TargetIP = (uint)0; - //kupack.TargetBlock.TargetPort = (ushort)0; - //kupack.UserInfo.Reason = gkupack.UserInfo.Reason; - - //OutPacket(kupack, ThrottleOutPacketType.Task); return true; } #endregion GodPackets diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index e0c492419c..db023792bd 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs @@ -152,7 +152,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods if (god == null || god.ControllingClient.SessionId != godSessionID) return String.Empty; - KickUser(godID, godSessionID, agentID, kickFlags, Util.StringToBytes1024(reason)); + KickUser(godID, agentID, kickFlags, Util.StringToBytes1024(reason)); } else { @@ -162,59 +162,53 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods } public void RequestGodlikePowers( - UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient) + UUID agentID, UUID sessionID, UUID token, bool godLike) { ScenePresence sp = m_scene.GetScenePresence(agentID); + if(sp == null || sp.IsDeleted || sp.isNPC) + return; - if (sp != null) - { - if (godLike == false) - { - sp.GrantGodlikePowers(agentID, sessionID, token, godLike); - return; - } + if (sessionID != sp.ControllingClient.SessionId) + return; - // First check that this is the sim owner - if (m_scene.Permissions.IsGod(agentID)) - { - // Next we check for spoofing..... - UUID testSessionID = sp.ControllingClient.SessionId; - if (sessionID == testSessionID) - { - if (sessionID == controllingClient.SessionId) - { - //m_log.Info("godlike: " + godLike.ToString()); - sp.GrantGodlikePowers(agentID, testSessionID, token, godLike); - } - } - } - else - { - if (DialogModule != null) - DialogModule.SendAlertToUser(agentID, "Request for god powers denied"); - } - } + sp.GrantGodlikePowers(token, godLike); + + if (godLike && sp.GodLevel < 200 && DialogModule != null) + DialogModule.SendAlertToUser(agentID, "Request for god powers denied"); } /// - /// Kicks User specified from the simulator. This logs them off of the grid - /// If the client gets the UUID: 44e87126e7944ded05b37c42da3d5cdb it assumes - /// that you're kicking it even if the avatar's UUID isn't the UUID that the - /// agent is assigned + /// Kicks or freezes User specified from the simulator. This logs them off of the grid /// /// The person doing the kicking - /// The session of the person doing the kicking /// the person that is being kicked /// Tells what to do to the user /// The message to send to the user after it's been turned into a field - public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason) + public void KickUser(UUID godID, UUID agentID, uint kickflags, byte[] reason) { - if (!m_scene.Permissions.IsGod(godID)) + // assuming automatic god rights on this for fast griefing reaction + // this is also needed for kick via message + if(!m_scene.Permissions.IsGod(godID)) return; - ScenePresence sp = m_scene.GetScenePresence(agentID); + int godlevel = 200; + // update level so higher gods can kick lower ones + ScenePresence god = m_scene.GetScenePresence(godID); + if(god != null && god.GodLevel > godlevel) + godlevel = god.GodLevel; - if (sp == null && agentID != ALL_AGENTS) + if(agentID == ALL_AGENTS) + { + m_scene.ForEachRootScenePresence(delegate(ScenePresence p) + { + if (p.UUID != godID && godlevel > p.GodLevel) + doKickmodes(godID, p, kickflags, reason); + }); + return; + } + + ScenePresence sp = m_scene.GetScenePresence(agentID); + if (sp == null || sp.IsChildAgent) { IMessageTransferModule transferModule = m_scene.RequestModuleInterface(); @@ -230,48 +224,41 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods return; } + if (godlevel <= sp.GodLevel) // no god wars + return; + + if(sp.UUID == godID) + return; + + doKickmodes(godID, sp, kickflags, reason); + } + + private void doKickmodes(UUID godID, ScenePresence sp, uint kickflags, byte[] reason) + { switch (kickflags) { - case 0: - if (sp != null) - { + case 0: KickPresence(sp, Utils.BytesToString(reason)); - } - else if (agentID == ALL_AGENTS) - { - m_scene.ForEachRootScenePresence( - delegate(ScenePresence p) - { - if (p.UUID != godID && (!m_scene.Permissions.IsGod(p.UUID))) - KickPresence(p, Utils.BytesToString(reason)); - } - ); - } - break; - case 1: - if (sp != null) - { + break; + case 1: sp.AllowMovement = false; - m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); + m_dialogModule.SendAlertToUser(sp.UUID, Utils.BytesToString(reason)); m_dialogModule.SendAlertToUser(godID, "User Frozen"); - } - break; - case 2: - if (sp != null) - { + break; + case 2: sp.AllowMovement = true; - m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); + m_dialogModule.SendAlertToUser(sp.UUID, Utils.BytesToString(reason)); m_dialogModule.SendAlertToUser(godID, "User Unfrozen"); - } - break; - default: - break; + break; + default: + break; } } + private void KickPresence(ScenePresence sp, string reason) { - if (sp.IsChildAgent) + if(sp.IsDeleted || sp.IsChildAgent) return; sp.ControllingClient.Kick(reason); sp.Scene.CloseAgent(sp.UUID, true); @@ -286,7 +273,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods UUID godID = new UUID(msg.fromAgentID); uint kickMode = (uint)msg.binaryBucket[0]; - KickUser(godID, UUID.Zero, agentID, kickMode, Util.StringToBytes1024(reason)); + KickUser(godID, agentID, kickMode, Util.StringToBytes1024(reason)); } } } diff --git a/OpenSim/Region/Framework/Interfaces/IGodsModule.cs b/OpenSim/Region/Framework/Interfaces/IGodsModule.cs index 552ce01199..1cb9a3002c 100644 --- a/OpenSim/Region/Framework/Interfaces/IGodsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IGodsModule.cs @@ -43,16 +43,15 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - void RequestGodlikePowers(UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient); + void RequestGodlikePowers(UUID agentID, UUID sessionID, UUID token, bool godLike); /// /// Kicks User specified from the simulator. This logs them off of the grid. /// /// The person doing the kicking - /// The session of the person doing the kicking /// the person that is being kicked /// This isn't used apparently /// The message to send to the user after it's been turned into a field - void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason); + void KickUser(UUID godID, UUID agentID, uint kickflags, byte[] reason); } } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index f906d9fed0..c1b1a6386d 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -4506,34 +4506,22 @@ namespace OpenSim.Region.Framework.Scenes #endregion /// - /// This allows the Sim owner the abiility to kick users from their sim currently. - /// It tells the client that the agent has permission to do so. + /// handle god level requests. /// - public void GrantGodlikePowers(UUID agentID, UUID sessionID, UUID token, bool godStatus) + public void GrantGodlikePowers(UUID token, bool godStatus) { int oldgodlevel = GodLevel; - - if (godStatus) + + if (godStatus && !isNPC && m_scene.Permissions.IsGod(UUID)) { - // For now, assign god level 200 to anyone - // who is granted god powers, but has no god level set. - // - UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, agentID); - if (account != null) - { - if (account.UserLevel > 0) - GodLevel = account.UserLevel; - else - GodLevel = 200; - } + GodLevel = 200; + if(GodLevel < UserLevel) + GodLevel = UserLevel; } else - { - GodLevel = 0; - } + GodLevel = 0; ControllingClient.SendAdminResponse(token, (uint)GodLevel); - if(oldgodlevel != GodLevel) parcelGodCheck(m_currentParcelUUID, GodLevel >= 200); } @@ -4640,7 +4628,7 @@ namespace OpenSim.Region.Framework.Scenes cAgent.BodyRotation = Rotation; cAgent.ControlFlags = (uint)m_AgentControlFlags; - if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID))) + if (GodLevel > 200 && m_scene.Permissions.IsGod(cAgent.AgentID)) cAgent.GodLevel = (byte)GodLevel; else cAgent.GodLevel = (byte) 0; @@ -4741,10 +4729,12 @@ namespace OpenSim.Region.Framework.Scenes Rotation = cAgent.BodyRotation; m_AgentControlFlags = (AgentManager.ControlFlags)cAgent.ControlFlags; - if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID))) + if (cAgent.GodLevel >200 && m_scene.Permissions.IsGod(cAgent.AgentID)) GodLevel = cAgent.GodLevel; - SetAlwaysRun = cAgent.AlwaysRun; + else + GodLevel = 0; + SetAlwaysRun = cAgent.AlwaysRun; Appearance = new AvatarAppearance(cAgent.Appearance); /* From de16ce35a38c4c19997951d2efce2dbbc20f6e0b Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 5 Jan 2017 18:05:06 +0000 Subject: [PATCH 250/305] Make the estate communications handler selectable Still defaults to the core EstateModule if not configured differently --- .../CoreModules/World/Estate/EstateModule.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs index 8eb38c2aa8..fb4d04f45f 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs @@ -52,6 +52,7 @@ namespace OpenSim.Region.CoreModules.World.Estate protected List m_Scenes = new List(); protected bool m_InInfoUpdate = false; private string token = "7db8eh2gvgg45jj"; + protected bool m_enabled = false; public bool InInfoUpdate { @@ -73,10 +74,19 @@ namespace OpenSim.Region.CoreModules.World.Estate IConfig estateConfig = config.Configs["Estates"]; if (estateConfig != null) { + if (estateConfig.GetString("EstateCommunicationsHandler", Name) == Name) + m_enabled = true; + else + return; + port = (uint)estateConfig.GetInt("Port", 0); // this will need to came from somewhere else token = estateConfig.GetString("Token", token); } + else + { + m_enabled = true; + } m_EstateConnector = new EstateConnector(this, token, port); @@ -98,12 +108,18 @@ namespace OpenSim.Region.CoreModules.World.Estate public void AddRegion(Scene scene) { + if (!m_enabled) + return; + lock (m_Scenes) m_Scenes.Add(scene); } public void RegionLoaded(Scene scene) { + if (!m_enabled) + return; + IEstateModule em = scene.RequestModuleInterface(); em.OnRegionInfoChange += OnRegionInfoChange; @@ -115,6 +131,9 @@ namespace OpenSim.Region.CoreModules.World.Estate public void RemoveRegion(Scene scene) { + if (!m_enabled) + return; + lock (m_Scenes) m_Scenes.Remove(scene); } From e88e2945e902a9f0edeb4f4d1b356ce77cdb4ee6 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 5 Jan 2017 18:53:02 +0000 Subject: [PATCH 251/305] Make it possible to disable the bakes module in the way it is described in config comments --- .../CoreModules/Avatar/BakedTextures/XBakesModule.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs b/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs index ea5bb64e91..6d97251f65 100644 --- a/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs @@ -53,6 +53,7 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures private UTF8Encoding enc = new UTF8Encoding(); private string m_URL = String.Empty; private static XmlSerializer m_serializer = new XmlSerializer(typeof(AssetBase)); + private static bool m_enabled = false; private static IServiceAuth m_Auth; @@ -63,11 +64,19 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures return; m_URL = config.GetString("URL", String.Empty); + if (m_URL == String.Empty) + return; + + m_enabled = true; + m_Auth = ServiceAuth.Create(configSource, "XBakes"); } public void AddRegion(Scene scene) { + if (!m_enabled) + return; + // m_log.InfoFormat("[XBakes]: Enabled for region {0}", scene.RegionInfo.RegionName); m_Scene = scene; @@ -211,4 +220,4 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures ); } } -} \ No newline at end of file +} From b16abc8166c29585cb76cc55c3bdd76e5833cb4f Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 5 Jan 2017 19:07:37 +0000 Subject: [PATCH 252/305] Massive tab and trailing space cleanup --- OpenSim/Addons/Groups/GroupsExtendedData.cs | 4 +- .../Addons/Groups/GroupsMessagingModule.cs | 32 +- OpenSim/Addons/Groups/GroupsModule.cs | 42 +- .../GroupsServiceHGConnectorModule.cs | 20 +- .../HGGroupsServiceRobustConnector.cs | 4 +- .../Addons/Groups/IGroupsServicesConnector.cs | 8 +- .../GroupsServiceLocalConnectorModule.cs | 10 +- .../Addons/Groups/Properties/AssemblyInfo.cs | 8 +- .../Remote/GroupsServiceRemoteConnector.cs | 4 +- .../GroupsServiceRemoteConnectorModule.cs | 14 +- .../Remote/GroupsServiceRobustConnector.cs | 12 +- .../Addons/Groups/Service/GroupsService.cs | 38 +- .../Groups/Service/GroupsServiceBase.cs | 110 +- .../Addons/Groups/Service/HGGroupsService.cs | 2 +- .../OfflineIM/Properties/AssemblyInfo.cs | 8 +- .../Remote/OfflineIMServiceRemoteConnector.cs | 4 +- .../OfflineIM/Service/OfflineIMService.cs | 2 +- .../LoadRegions/LoadRegionsPlugin.cs | 2 +- .../LoadRegions/RegionLoaderFileSystem.cs | 20 +- .../Properties/AssemblyInfo.cs | 8 +- .../RegionModulesControllerPlugin.cs | 12 +- .../Properties/AssemblyInfo.cs | 8 +- .../RemoteController/RemoteAdminPlugin.cs | 50 +- OpenSim/Capabilities/Caps.cs | 8 +- OpenSim/Capabilities/CapsHandlers.cs | 6 +- .../AvatarPickerSearchHandler.cs | 2 +- .../FetchInventory/FetchInvDescHandler.cs | 16 +- .../FetchInventory/FetchInventory2Handler.cs | 2 +- .../Tests/FetchInventory2HandlerTests.cs | 2 +- .../FetchInventoryDescendents2HandlerTests.cs | 4 +- .../GetDisplayNames/GetDisplayNamesHandler.cs | 4 +- .../GetDisplayNamesServerConnector.cs | 2 +- .../Handlers/GetTexture/GetTextureHandler.cs | 12 +- .../GetTexture/GetTextureRobustHandler.cs | 96 +- .../Handlers/Properties/AssemblyInfo.cs | 8 +- .../UploadBakedTextureHandler.cs | 8 +- .../Capabilities/LLSDAssetUploadResponse.cs | 2 +- OpenSim/Capabilities/LLSDAvatarPicker.cs | 2 +- OpenSim/Capabilities/LLSDInventoryItem.cs | 6 +- .../Capabilities/Properties/AssemblyInfo.cs | 8 +- OpenSim/ConsoleClient/ConsoleClient.cs | 4 +- .../ConsoleClient/Properties/AssemblyInfo.cs | 8 +- OpenSim/Data/DBGuids.cs | 2 +- OpenSim/Data/IAvatarData.cs | 2 +- OpenSim/Data/IEstateDataStore.cs | 16 +- OpenSim/Data/IGridUserData.cs | 2 +- OpenSim/Data/IGroupsData.cs | 2 +- OpenSim/Data/IHGTravelingData.cs | 2 +- OpenSim/Data/IOfflineIMData.cs | 2 +- OpenSim/Data/IPresenceData.cs | 2 +- OpenSim/Data/IRegionData.cs | 2 +- OpenSim/Data/IXGroupData.cs | 6 +- OpenSim/Data/Migration.cs | 26 +- OpenSim/Data/MySQL/MySQLAssetData.cs | 4 +- OpenSim/Data/MySQL/MySQLAuthenticationData.cs | 28 +- OpenSim/Data/MySQL/MySQLAvatarData.cs | 2 +- OpenSim/Data/MySQL/MySQLEstateData.cs | 14 +- OpenSim/Data/MySQL/MySQLFSAssetData.cs | 2 +- .../Data/MySQL/MySQLGenericTableHandler.cs | 20 +- OpenSim/Data/MySQL/MySQLGroupsData.cs | 20 +- OpenSim/Data/MySQL/MySQLInventoryData.cs | 12 +- OpenSim/Data/MySQL/MySQLMigrations.cs | 6 +- OpenSim/Data/MySQL/MySQLOfflineIMData.cs | 2 +- OpenSim/Data/MySQL/MySQLPresenceData.cs | 8 +- OpenSim/Data/MySQL/MySQLRegionData.cs | 2 +- OpenSim/Data/MySQL/MySQLSimulationData.cs | 30 +- OpenSim/Data/MySQL/MySQLUserProfilesData.cs | 176 +- OpenSim/Data/MySQL/MySQLXAssetData.cs | 6 +- OpenSim/Data/MySQL/MySQLXInventoryData.cs | 6 +- OpenSim/Data/Null/NullEstateData.cs | 6 +- OpenSim/Data/Null/NullFriendsData.cs | 10 +- OpenSim/Data/Null/NullPresenceData.cs | 8 +- OpenSim/Data/Null/NullUserAccountData.cs | 32 +- OpenSim/Data/PGSQL/PGSQLAssetData.cs | 18 +- OpenSim/Data/PGSQL/PGSQLAuthenticationData.cs | 6 +- OpenSim/Data/PGSQL/PGSQLAvatarData.cs | 2 +- OpenSim/Data/PGSQL/PGSQLEstateData.cs | 2 +- OpenSim/Data/PGSQL/PGSQLFriendsData.cs | 6 +- .../Data/PGSQL/PGSQLGenericTableHandler.cs | 14 +- OpenSim/Data/PGSQL/PGSQLGroupsData.cs | 36 +- OpenSim/Data/PGSQL/PGSQLInventoryData.cs | 58 +- OpenSim/Data/PGSQL/PGSQLManager.cs | 2 +- OpenSim/Data/PGSQL/PGSQLMigration.cs | 4 +- OpenSim/Data/PGSQL/PGSQLOfflineIMData.cs | 2 +- OpenSim/Data/PGSQL/PGSQLPresenceData.cs | 4 +- OpenSim/Data/PGSQL/PGSQLRegionData.cs | 14 +- OpenSim/Data/PGSQL/PGSQLSimulationData.cs | 156 +- OpenSim/Data/PGSQL/PGSQLUserAccountData.cs | 20 +- OpenSim/Data/PGSQL/PGSQLUserProfilesData.cs | 12 +- OpenSim/Data/PGSQL/PGSQLXAssetData.cs | 24 +- OpenSim/Data/PGSQL/PGSQLXInventoryData.cs | 14 +- OpenSim/Data/SQLite/SQLiteAssetData.cs | 4 +- .../Data/SQLite/SQLiteAuthenticationData.cs | 6 +- OpenSim/Data/SQLite/SQLiteEstateData.cs | 12 +- .../Data/SQLite/SQLiteGenericTableHandler.cs | 4 +- OpenSim/Data/SQLite/SQLiteGridUserData.cs | 2 +- OpenSim/Data/SQLite/SQLiteHGTravelData.cs | 2 +- OpenSim/Data/SQLite/SQLiteSimulationData.cs | 16 +- OpenSim/Data/SQLite/SQLiteUserAccountData.cs | 2 +- OpenSim/Data/SQLite/SQLiteUserProfilesData.cs | 166 +- OpenSim/Data/SQLite/SQLiteUtils.cs | 6 +- OpenSim/Data/SQLite/SQLiteXInventoryData.cs | 4 +- OpenSim/Data/Tests/AssetTests.cs | 6 +- OpenSim/Data/Tests/BasicDataServiceTest.cs | 12 +- OpenSim/Data/Tests/DefaultTestConns.cs | 10 +- OpenSim/Data/Tests/EstateTests.cs | 18 +- OpenSim/Data/Tests/InventoryTests.cs | 28 +- OpenSim/Data/Tests/PropertyScrambler.cs | 2 +- OpenSim/Data/Tests/RegionTests.cs | 152 +- OpenSim/Framework/AgentCircuitData.cs | 6 +- OpenSim/Framework/AnimationSet.cs | 2 +- OpenSim/Framework/AssetBase.cs | 6 +- .../Filesystem/Properties/AssemblyInfo.cs | 8 +- OpenSim/Framework/AssetRequestToClient.cs | 6 +- OpenSim/Framework/AvatarAppearance.cs | 48 +- OpenSim/Framework/AvatarWearable.cs | 8 +- OpenSim/Framework/BasicDOSProtector.cs | 14 +- OpenSim/Framework/BlockingQueue.cs | 2 +- OpenSim/Framework/Cache.cs | 4 +- OpenSim/Framework/CapsUtil.cs | 2 +- OpenSim/Framework/ChildAgentDataUpdate.cs | 8 +- OpenSim/Framework/CircularBuffer.cs | 20 +- OpenSim/Framework/CnmMemoryCache.cs | 140 +- OpenSim/Framework/CnmSynchronizedCache.cs | 106 +- OpenSim/Framework/Console/CommandConsole.cs | 40 +- OpenSim/Framework/Console/ConsoleBase.cs | 8 +- OpenSim/Framework/Console/ConsoleUtil.cs | 22 +- OpenSim/Framework/Console/LocalConsole.cs | 22 +- OpenSim/Framework/Console/MockConsole.cs | 4 +- OpenSim/Framework/Console/RemoteConsole.cs | 372 +-- OpenSim/Framework/DAMap.cs | 40 +- OpenSim/Framework/DOMap.cs | 2 +- .../DoubleDictionaryThreadAbortSafe.cs | 124 +- OpenSim/Framework/EstateBan.cs | 2 +- OpenSim/Framework/EstateSettings.cs | 2 +- OpenSim/Framework/GridInstantMessage.cs | 2 +- OpenSim/Framework/IClientAPI.cs | 72 +- OpenSim/Framework/ICnmCache.cs | 106 +- OpenSim/Framework/ILandChannel.cs | 6 +- OpenSim/Framework/ILandObject.cs | 32 +- OpenSim/Framework/IPrimCounts.cs | 14 +- OpenSim/Framework/IRegistryCore.cs | 2 +- OpenSim/Framework/IScene.cs | 4 +- OpenSim/Framework/ISceneAgent.cs | 2 +- OpenSim/Framework/InventoryFolderImpl.cs | 2 +- OpenSim/Framework/InventoryItemBase.cs | 110 +- OpenSim/Framework/InventoryNodeBase.cs | 8 +- OpenSim/Framework/LandData.cs | 8 +- OpenSim/Framework/Lazy.cs | 4 +- OpenSim/Framework/LocklessQueue.cs | 2 +- OpenSim/Framework/MapAndArray.cs | 12 +- OpenSim/Framework/MapItemReplyStruct.cs | 2 +- OpenSim/Framework/MetricsCollector.cs | 8 +- .../Monitoring/BaseStatsCollector.cs | 2 +- OpenSim/Framework/Monitoring/Checks/Check.cs | 8 +- .../Monitoring/Interfaces/IStatsCollector.cs | 2 +- OpenSim/Framework/Monitoring/JobEngine.cs | 10 +- .../Monitoring/Properties/AssemblyInfo.cs | 8 +- .../Monitoring/ServerStatsCollector.cs | 26 +- .../Monitoring/SimExtraStatsCollector.cs | 28 +- OpenSim/Framework/Monitoring/Stats/Stat.cs | 38 +- OpenSim/Framework/Monitoring/StatsLogger.cs | 6 +- OpenSim/Framework/Monitoring/StatsManager.cs | 4 +- OpenSim/Framework/Monitoring/Watchdog.cs | 2 +- OpenSim/Framework/Monitoring/WorkManager.cs | 32 +- OpenSim/Framework/NetworkUtil.cs | 4 +- OpenSim/Framework/OutboundUrlFilter.cs | 16 +- OpenSim/Framework/PluginManager.cs | 54 +- OpenSim/Framework/PrimeNumberHelper.cs | 2 +- OpenSim/Framework/PrimitiveBaseShape.cs | 4 +- OpenSim/Framework/PriorityQueue.cs | 24 +- OpenSim/Framework/RegionInfo.cs | 30 +- OpenSim/Framework/RegionSettings.cs | 18 +- OpenSim/Framework/RestClient.cs | 2 +- OpenSim/Framework/SLUtil.cs | 14 +- .../Serialization/ArchiveConstants.cs | 4 +- .../External/ExternalRepresentationUtils.cs | 6 +- .../Serialization/External/OspResolver.cs | 44 +- .../External/RegionSettingsSerializer.cs | 34 +- .../External/UserInventoryItemSerializer.cs | 22 +- .../External/UserProfileSerializer.cs | 12 +- .../Serialization/Properties/AssemblyInfo.cs | 8 +- .../Serialization/TarArchiveWriter.cs | 12 +- .../Framework/Servers/BaseOpenSimServer.cs | 30 +- .../Servers/HttpServer/BaseHttpServer.cs | 46 +- .../Servers/HttpServer/BaseRequestHandler.cs | 14 +- .../Servers/HttpServer/BaseStreamHandler.cs | 4 +- .../BaseStreamHandlerBasicDOSProtector.cs | 8 +- .../GenericHTTPBasicDOSProtector.cs | 6 +- .../HttpServer/Interfaces/IHttpServer.cs | 34 +- .../HttpServer/Interfaces/IStreamHandler.cs | 2 +- .../HttpServer/JsonRpcRequestManager.cs | 4 +- .../Servers/HttpServer/JsonRpcResponse.cs | 2 +- .../Servers/HttpServer/OSHttpRequest.cs | 12 +- .../Servers/HttpServer/OSHttpResponse.cs | 2 +- .../Servers/HttpServer/OSHttpStatusCodes.cs | 2 +- .../HttpServer/PollServiceEventArgs.cs | 4 +- .../HttpServer/PollServiceRequestManager.cs | 4 +- .../HttpServer/Properties/AssemblyInfo.cs | 8 +- .../Servers/HttpServer/RestSessionService.cs | 2 +- .../HttpServer/WebsocketServerHandler.cs | 82 +- .../HttpServer/XmlRpcBasicDOSProtector.cs | 6 +- OpenSim/Framework/Servers/MainServer.cs | 14 +- .../Servers/Properties/AssemblyInfo.cs | 8 +- OpenSim/Framework/Servers/ServerBase.cs | 52 +- .../Framework/Servers/Tests/OSHttpTests.cs | 136 +- .../ServiceAuth/BasicHttpAuthentication.cs | 2 +- .../ServiceAuth/CompoundAuthentication.cs | 2 +- OpenSim/Framework/SimStats.cs | 10 +- OpenSim/Framework/TaskInventoryDictionary.cs | 6 +- OpenSim/Framework/TaskInventoryItem.cs | 2 +- .../Framework/Tests/AgentCircuitDataTest.cs | 8 +- .../Tests/AgentCircuitManagerTests.cs | 2 +- OpenSim/Framework/Tests/AnimationTests.cs | 2 +- OpenSim/Framework/Tests/CacheTests.cs | 4 +- OpenSim/Framework/Tests/LocationTest.cs | 2 +- .../Framework/Tests/MundaneFrameworkTests.cs | 12 +- .../Framework/Tests/PrimeNumberHelperTests.cs | 6 +- OpenSim/Framework/Tests/UtilTest.cs | 2 +- OpenSim/Framework/UserProfileData.cs | 10 +- OpenSim/Framework/UserProfiles.cs | 12 +- OpenSim/Framework/Util.cs | 86 +- OpenSim/Framework/VersionInfo.cs | 12 +- OpenSim/Framework/WearableCacheItem.cs | 6 +- OpenSim/Framework/WebUtil.cs | 60 +- OpenSim/Region/Application/Application.cs | 58 +- .../Region/Application/ConfigurationLoader.cs | 14 +- .../Region/Application/IApplicationPlugin.cs | 2 +- OpenSim/Region/Application/OpenSim.cs | 76 +- OpenSim/Region/Application/OpenSimBase.cs | 84 +- .../Application/Properties/AssemblyInfo.cs | 8 +- .../Application/RegionApplicationBase.cs | 12 +- .../Linden/Caps/AgentPreferencesModule.cs | 2 +- .../Linden/Caps/AvatarPickerSearchModule.cs | 2 +- .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 60 +- .../Caps/BunchOfCaps/BunchOfCapsModule.cs | 4 +- .../Linden/Caps/BunchOfCaps/MeshCost.cs | 30 +- .../Caps/EventQueue/EventQueueGetModule.cs | 38 +- .../Caps/EventQueue/EventQueueHelper.cs | 14 +- .../Caps/EventQueue/Tests/EventQueueTests.cs | 2 +- .../ClientStack/Linden/Caps/GetMeshModule.cs | 14 +- .../Linden/Caps/GetTextureModule.cs | 30 +- .../Linden/Caps/MeshUploadFlagModule.cs | 4 +- .../Linden/Caps/ObjectCaps/ObjectAdd.cs | 4 +- .../ObjectCaps/UploadObjectAssetModule.cs | 16 +- .../Linden/Caps/Properties/AssemblyInfo.cs | 8 +- .../Linden/Caps/RegionConsoleModule.cs | 4 +- .../Linden/Caps/SimulatorFeaturesModule.cs | 6 +- .../Caps/Tests/WebFetchInvDescModuleTests.cs | 2 +- .../Linden/Caps/UploadBakedTextureModule.cs | 10 +- .../Linden/Caps/WebFetchInvDescModule.cs | 2 +- .../Region/ClientStack/Linden/UDP/J2KImage.cs | 4 +- .../ClientStack/Linden/UDP/LLClientView.cs | 242 +- .../ClientStack/Linden/UDP/LLImageManager.cs | 2 +- .../ClientStack/Linden/UDP/LLUDPClient.cs | 36 +- .../ClientStack/Linden/UDP/LLUDPServer.cs | 76 +- .../Linden/UDP/LLUDPServerCommands.cs | 52 +- .../ClientStack/Linden/UDP/OpenSimUDPBase.cs | 82 +- .../ClientStack/Linden/UDP/PacketPool.cs | 10 +- .../Linden/UDP/Properties/AssemblyInfo.cs | 8 +- .../Linden/UDP/Tests/BasicCircuitTests.cs | 44 +- .../Linden/UDP/Tests/PacketHandlerTests.cs | 8 +- .../Linden/UDP/Tests/ThrottleTests.cs | 58 +- .../ClientStack/Linden/UDP/ThrottleRates.cs | 6 +- .../ClientStack/Linden/UDP/TokenBucket.cs | 52 +- .../Linden/UDP/UnackedPacketCollection.cs | 14 +- .../ClientStack/Properties/AssemblyInfo.cs | 8 +- .../AgentAssetsTransactions.cs | 2 +- .../AssetTransactionModule.cs | 6 +- .../AssetTransaction/AssetXferUploader.cs | 2 +- .../CoreModules/Agent/IPBan/IPBanModule.cs | 8 +- .../Agent/TextureSender/J2KDecoderModule.cs | 2 +- .../CoreModules/Agent/Xfer/XferModule.cs | 14 +- .../CoreModules/Asset/CenomeAssetCache.cs | 22 +- .../CoreModules/Asset/CoreAssetCache.cs | 2 +- .../CoreModules/Asset/FlotsamAssetCache.cs | 70 +- .../Asset/GlynnTuckerAssetCache.cs | 2 +- .../Asset/Tests/FlotsamAssetCacheTests.cs | 2 +- .../Avatar/Attachments/AttachmentsModule.cs | 78 +- .../Tests/AttachmentsModuleTests.cs | 6 +- .../AvatarFactory/AvatarFactoryModule.cs | 42 +- .../Tests/AvatarFactoryModuleTests.cs | 16 +- .../Avatar/BakedTextures/XBakesModule.cs | 14 +- .../CoreModules/Avatar/Chat/ChatModule.cs | 30 +- .../Avatar/Chat/Tests/ChatModuleTests.cs | 52 +- .../Avatar/Commands/UserCommandsModule.cs | 8 +- .../Avatar/Friends/FriendsModule.cs | 16 +- .../Avatar/Friends/FriendsRequestHandler.cs | 2 +- .../Avatar/Friends/HGFriendsModule.cs | 14 +- .../Avatar/Friends/HGStatusNotifier.cs | 2 +- .../Avatar/Friends/Tests/FriendModuleTests.cs | 2 +- .../Avatar/Gestures/GesturesModule.cs | 14 +- .../CoreModules/Avatar/Gods/GodsModule.cs | 10 +- .../CoreModules/Avatar/Groups/GroupsModule.cs | 2 +- .../InstantMessage/HGMessageTransferModule.cs | 6 +- .../InstantMessage/InstantMessageModule.cs | 4 +- .../InstantMessage/MessageTransferModule.cs | 6 +- .../Avatar/InstantMessage/MuteListModule.cs | 4 +- .../InstantMessage/OfflineMessageModule.cs | 2 +- .../Archiver/InventoryArchiveReadRequest.cs | 160 +- .../Archiver/InventoryArchiveUtils.cs | 38 +- .../Archiver/InventoryArchiverModule.cs | 2 +- .../Tests/InventoryArchiveLoadPathTests.cs | 114 +- .../Tests/InventoryArchiveLoadTests.cs | 84 +- .../Tests/InventoryArchiveSaveTests.cs | 60 +- .../Tests/InventoryArchiveTestCase.cs | 74 +- .../Transfer/InventoryTransferModule.cs | 44 +- .../Tests/InventoryTransferModuleTests.cs | 178 +- .../CoreModules/Avatar/Lure/HGLureModule.cs | 6 +- .../Avatar/Profile/BasicProfileModule.cs | 2 +- .../Avatar/UserProfiles/UserProfileModule.cs | 60 +- .../Framework/Caps/CapabilitiesModule.cs | 48 +- .../DynamicAttributes/DAExampleModule.cs | 30 +- .../DynamicAttributes/DOExampleModule.cs | 24 +- .../EntityTransfer/EntityTransferModule.cs | 104 +- .../EntityTransferStateMachine.cs | 12 +- .../EntityTransfer/HGEntityTransferModule.cs | 46 +- .../Framework/InterfaceCommander/Commander.cs | 20 +- .../InventoryAccess/HGAssetMapper.cs | 8 +- .../HGInventoryAccessModule.cs | 16 +- .../InventoryAccess/InventoryAccessModule.cs | 78 +- .../Tests/HGAssetMapperTests.cs | 8 +- .../Tests/InventoryAccessModuleTests.cs | 62 +- .../Framework/Library/LibraryModule.cs | 2 +- .../Library/LocalInventoryService.cs | 4 +- .../Framework/Monitoring/MonitorModule.cs | 8 +- .../Framework/Search/BasicSearchModule.cs | 2 +- .../ServiceThrottle/ServiceThrottleModule.cs | 2 +- .../Statistics/Logging/BinaryLoggingModule.cs | 24 +- .../UserManagement/HGUserManagementModule.cs | 10 +- .../Tests/HGUserManagementModuleTests.cs | 2 +- .../UserManagement/UserManagementModule.cs | 4 +- .../CoreModules/Hypergrid/HGWorldMapModule.cs | 2 +- .../CoreModules/Properties/AssemblyInfo.cs | 8 +- .../DynamicTexture/DynamicTextureModule.cs | 14 +- .../HttpRequest/ScriptsHttpRequests.cs | 10 +- .../Tests/ScriptsHttpRequestsTests.cs | 22 +- .../Scripting/LSLHttp/UrlModule.cs | 38 +- .../LoadImageURL/LoadImageURLModule.cs | 16 +- .../ScriptModuleCommsModule.cs | 8 +- .../VectorRender/VectorRenderModule.cs | 56 +- .../Scripting/WorldComm/WorldCommModule.cs | 2 +- .../Scripting/XMLRPC/XMLRPCModule.cs | 4 +- .../Asset/AssetServiceInConnectorModule.cs | 6 +- .../AuthenticationServiceInConnectorModule.cs | 4 +- .../Grid/GridInfoServiceInConnectorModule.cs | 4 +- .../HypergridServiceInConnectorModule.cs | 6 +- .../InventoryServiceInConnectorModule.cs | 4 +- .../Land/LandServiceInConnectorModule.cs | 2 +- .../Login/LLLoginServiceInConnectorModule.cs | 4 +- .../MapImageServiceInConnectorModule.cs | 4 +- .../NeighbourServiceInConnectorModule.cs | 2 +- .../SimulationServiceInConnectorModule.cs | 2 +- .../LocalUserProfilesServiceConnector.cs | 28 +- .../LocalAgentPreferencesServiceConnector.cs | 2 +- .../RemoteAgentPreferencesServiceConnector.cs | 4 +- .../Asset/HGAssetBroker.cs | 20 +- .../Asset/LocalAssetServiceConnector.cs | 14 +- .../Asset/RemoteAssetServiceConnector.cs | 2 +- .../LocalAuthenticationServiceConnector.cs | 6 +- .../RemoteAuthenticationServiceConnector.cs | 2 +- .../LocalAuthorizationServiceConnector.cs | 4 +- .../RemoteAuthorizationServiceConnector.cs | 16 +- .../Avatar/LocalAvatarServiceConnector.cs | 8 +- .../Avatar/RemoteAvatarServiceConnector.cs | 2 +- .../Grid/LocalGridServiceConnector.cs | 14 +- .../Grid/RegionInfoCache.cs | 66 +- .../Grid/RemoteGridServiceConnector.cs | 22 +- .../Grid/Tests/GridConnectorsTests.cs | 2 +- .../GridUser/ActivityDetector.cs | 4 +- .../Inventory/HGInventoryBroker.cs | 4 +- .../LocalInventoryServiceConnector.cs | 10 +- .../RemoteXInventoryServiceConnector.cs | 2 +- .../Land/LocalLandServiceConnector.cs | 2 +- .../Land/RemoteLandServiceConnector.cs | 2 +- .../MapImage/MapImageServiceModule.cs | 14 +- .../LocalNeighbourServiceConnector.cs | 4 +- .../RemoteNeighourServiceConnector.cs | 2 +- .../Presence/PresenceDetector.cs | 4 +- .../Presence/Tests/PresenceConnectorsTests.cs | 2 +- .../Simulation/LocalSimulationConnector.cs | 4 +- .../Simulation/RemoteSimulationConnector.cs | 4 +- .../LocalUserAccountServiceConnector.cs | 4 +- .../RemoteUserAccountServiceConnector.cs | 2 +- .../UserAccounts/UserAccountCache.cs | 6 +- .../CoreModules/World/Access/AccessModule.cs | 2 +- .../World/Archiver/ArchiveReadRequest.cs | 46 +- .../World/Archiver/ArchiveScenesGroup.cs | 4 +- .../World/Archiver/ArchiveWriteRequest.cs | 52 +- .../World/Archiver/ArchiverModule.cs | 22 +- .../World/Archiver/AssetsArchiver.cs | 6 +- .../World/Archiver/AssetsRequest.cs | 46 +- .../World/Archiver/DearchiveScenesGroup.cs | 2 +- .../World/Archiver/Tests/ArchiverTests.cs | 98 +- .../CoreModules/World/Cloud/CloudModule.cs | 24 +- .../World/Estate/EstateConnector.cs | 2 +- .../World/Estate/EstateManagementCommands.cs | 38 +- .../World/Estate/EstateManagementModule.cs | 62 +- .../CoreModules/World/Estate/EstateModule.cs | 30 +- .../CoreModules/World/Land/LandChannel.cs | 12 +- .../World/Land/LandManagementModule.cs | 74 +- .../CoreModules/World/Land/LandObject.cs | 50 +- .../CoreModules/World/Land/PrimCountModule.cs | 138 +- .../Land/Tests/LandManagementModuleTests.cs | 40 +- .../World/Land/Tests/PrimCountModuleTests.cs | 224 +- .../World/LegacyMap/MapImageModule.cs | 14 +- .../LegacyMap/TexturedMapTileRenderer.cs | 4 +- .../World/Media/Moap/MoapModule.cs | 252 +- .../World/Media/Moap/Tests/MoapTests.cs | 36 +- .../World/Objects/BuySell/BuySellModule.cs | 18 +- .../Objects/Commands/ObjectCommandsModule.cs | 54 +- .../World/Permissions/PermissionsModule.cs | 214 +- .../World/Region/RegionCommandsModule.cs | 18 +- .../CoreModules/World/Region/RestartModule.cs | 16 +- .../World/Serialiser/SerialiserModule.cs | 10 +- .../World/Serialiser/Tests/SerialiserTests.cs | 24 +- .../CoreModules/World/Sound/SoundModule.cs | 6 +- .../Region/CoreModules/World/Sun/SunModule.cs | 12 +- .../FileLoaders/GenericSystemDrawing.cs | 2 +- .../World/Terrain/FileLoaders/JPEG.cs | 4 +- .../World/Terrain/FileLoaders/LLRAW.cs | 2 +- .../World/Terrain/ITerrainFloodEffect.cs | 2 +- .../World/Terrain/ITerrainLoader.cs | 2 +- .../Terrain/PaintBrushes/FlattenSphere.cs | 2 +- .../World/Terrain/PaintBrushes/LowerSphere.cs | 2 +- .../World/Terrain/PaintBrushes/RaiseSphere.cs | 2 +- .../Terrain/PaintBrushes/RevertSphere.cs | 2 +- .../Terrain/PaintBrushes/SmoothSphere.cs | 4 +- .../World/Terrain/TerrainModule.cs | 14 +- .../World/Terrain/Tests/TerrainModuleTests.cs | 4 +- .../World/Vegetation/VegetationModule.cs | 22 +- .../World/Warp3DMap/TerrainSplat.cs | 4 +- .../World/Warp3DMap/Warp3DImageModule.cs | 22 +- .../World/Wind/Plugins/ConfigurableWind.cs | 12 +- .../CoreModules/World/Wind/WindModule.cs | 10 +- .../World/WorldMap/MapSearchModule.cs | 4 +- .../World/WorldMap/WorldMapModule.cs | 12 +- .../Interfaces/IAgentAssetTransactions.cs | 2 +- .../Interfaces/IAttachmentsModule.cs | 4 +- .../Framework/Interfaces/IBuySellModule.cs | 2 +- .../Interfaces/ICapabilitiesModule.cs | 12 +- .../Framework/Interfaces/ICloudModule.cs | 2 +- .../Region/Framework/Interfaces/ICommander.cs | 4 +- .../Interfaces/IDynamicFloaterModule.cs | 2 +- .../Interfaces/IDynamicTextureManager.cs | 4 +- .../Framework/Interfaces/IEntityCreator.cs | 2 +- .../Framework/Interfaces/IEntityInventory.cs | 20 +- .../Interfaces/IEntityTransferModule.cs | 4 +- .../Framework/Interfaces/IEventQueue.cs | 6 +- .../Interfaces/IExternalCapsModule.cs | 2 +- .../Framework/Interfaces/IGodsModule.cs | 2 +- .../Interfaces/IGroupsMessagingModule.cs | 12 +- .../Framework/Interfaces/IGroupsModule.cs | 6 +- .../Framework/Interfaces/IHttpRequests.cs | 2 +- .../Framework/Interfaces/IJsonStoreModule.cs | 6 +- .../Interfaces/IMessageTransferModule.cs | 2 +- .../Framework/Interfaces/IMoapModule.cs | 8 +- .../Region/Framework/Interfaces/INPCModule.cs | 4 +- .../Interfaces/IPermissionsModule.cs | 2 +- .../Framework/Interfaces/IPresenceModule.cs | 2 +- .../Interfaces/IRegionArchiverModule.cs | 38 +- .../Framework/Interfaces/IRegionModuleBase.cs | 2 +- .../Interfaces/IRegionSerialiserModule.cs | 4 +- .../Interfaces/ISimulationDataStore.cs | 8 +- .../Framework/Interfaces/ISnmpModule.cs | 6 +- .../Framework/Interfaces/ITerrainModule.cs | 4 +- .../Region/Framework/Interfaces/IUrlModule.cs | 2 +- .../Framework/Interfaces/IVoiceModule.cs | 2 +- .../Framework/Interfaces/IWindModule.cs | 2 +- .../Region/Framework/Interfaces/IWorldComm.cs | 2 +- .../Framework/Properties/AssemblyInfo.cs | 8 +- .../Scenes/Animation/AnimationSet.cs | 18 +- .../Scenes/Animation/BinBVHAnimation.cs | 40 +- .../Animation/DefaultAvatarAnimations.cs | 2 +- .../Scenes/Animation/ScenePresenceAnimator.cs | 6 +- .../Framework/Scenes/AsyncInventorySender.cs | 4 +- .../Scenes/AsyncSceneObjectGroupDeleter.cs | 38 +- .../Framework/Scenes/CoalescedSceneObjects.cs | 40 +- .../Framework/Scenes/CollisionSounds.cs | 2 +- .../Region/Framework/Scenes/EntityManager.cs | 4 +- .../Region/Framework/Scenes/EventManager.cs | 260 +- .../Region/Framework/Scenes/KeyframeMotion.cs | 8 +- .../Region/Framework/Scenes/Prioritizer.cs | 30 +- .../Framework/Scenes/RegionStatsHandler.cs | 8 +- .../Region/Framework/Scenes/SOPMaterial.cs | 2 +- OpenSim/Region/Framework/Scenes/SOPVehicle.cs | 2 +- .../Framework/Scenes/Scene.Inventory.cs | 82 +- .../Framework/Scenes/Scene.PacketHandlers.cs | 32 +- .../Framework/Scenes/Scene.Permissions.cs | 58 +- OpenSim/Region/Framework/Scenes/Scene.cs | 192 +- OpenSim/Region/Framework/Scenes/SceneBase.cs | 18 +- .../Scenes/SceneCommunicationService.cs | 6 +- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 58 +- .../Region/Framework/Scenes/SceneManager.cs | 10 +- .../Scenes/SceneObjectGroup.Inventory.cs | 26 +- .../Framework/Scenes/SceneObjectGroup.cs | 192 +- .../Framework/Scenes/SceneObjectPart.cs | 244 +- .../Scenes/SceneObjectPartInventory.cs | 58 +- .../Region/Framework/Scenes/ScenePresence.cs | 278 +- .../Scenes/ScenePresenceStateMachine.cs | 6 +- .../CoalescedSceneObjectsSerializer.cs | 60 +- .../Serialization/SceneObjectSerializer.cs | 28 +- .../Framework/Scenes/SimStatsReporter.cs | 46 +- .../Region/Framework/Scenes/TerrainChannel.cs | 4 +- .../Framework/Scenes/TerrainCompressor.cs | 16 +- .../Scenes/Tests/EntityManagerTests.cs | 22 +- .../Framework/Scenes/Tests/SceneGraphTests.cs | 18 +- .../Scenes/Tests/SceneObjectBasicTests.cs | 28 +- .../Scenes/Tests/SceneObjectCopyTests.cs | 32 +- .../Scenes/Tests/SceneObjectCrossingTests.cs | 2 +- .../Scenes/Tests/SceneObjectDeRezTests.cs | 38 +- .../Scenes/Tests/SceneObjectLinkingTests.cs | 54 +- .../Scenes/Tests/SceneObjectSpatialTests.cs | 2 +- .../Scenes/Tests/SceneObjectStatusTests.cs | 10 +- .../Scenes/Tests/SceneObjectUserGroupTests.cs | 32 +- .../Scenes/Tests/ScenePresenceAgentTests.cs | 8 +- .../Tests/ScenePresenceTeleportTests.cs | 6 +- .../Scenes/Tests/SceneTelehubTests.cs | 4 +- .../Framework/Scenes/Tests/SceneTests.cs | 4 +- .../Scenes/Tests/SharedRegionModuleTests.cs | 18 +- .../Scenes/Tests/TaskInventoryTests.cs | 20 +- .../Scenes/Tests/UserInventoryTests.cs | 2 +- .../Scenes/Tests/UuidGathererTests.cs | 18 +- OpenSim/Region/Framework/Scenes/UndoState.cs | 12 +- .../Region/Framework/Scenes/UuidGatherer.cs | 28 +- .../Server/IRCClientView.cs | 254 +- .../TextureSender/J2KDecoderCommandModule.cs | 20 +- .../Agent/UDP/Linden/LindenUDPInfoModule.cs | 182 +- .../OptionalModules/Asset/AssetInfoModule.cs | 32 +- .../Animations/AnimationsCommandModule.cs | 28 +- .../Avatar/Appearance/AppearanceInfoModule.cs | 42 +- .../Attachments/AttachmentsCommandModule.cs | 20 +- .../Attachments/TempAttachmentsModule.cs | 4 +- .../Avatar/Chat/ChannelState.cs | 22 +- .../Avatar/Chat/IRCConnector.cs | 16 +- .../Avatar/Chat/RegionState.cs | 4 +- .../Avatar/Concierge/ConciergeModule.cs | 40 +- .../Avatar/Friends/FriendsCommandsModule.cs | 16 +- .../Avatar/SitStand/SitStandCommandsModule.cs | 22 +- .../FreeSwitchVoice/FreeSwitchVoiceModule.cs | 60 +- .../Voice/VivoxVoice/VivoxVoiceModule.cs | 118 +- .../XmlRpcGroups/GroupsMessagingModule.cs | 60 +- .../Avatar/XmlRpcGroups/GroupsModule.cs | 48 +- .../XmlRpcGroups/IGroupsServicesConnector.cs | 4 +- .../SimianGroupsServicesConnectorModule.cs | 94 +- .../XmlRpcGroups/Tests/GroupsModuleTests.cs | 16 +- .../XmlRpcGroupsServicesConnectorModule.cs | 22 +- .../DataSnapshot/DataSnapshotManager.cs | 4 +- .../DataSnapshot/LandSnapshot.cs | 2 +- .../BareBonesNonSharedModule.cs | 28 +- .../BareBonesShared/BareBonesSharedModule.cs | 32 +- .../WebSocketEchoTest/WebSocketEchoModule.cs | 10 +- .../Monitoring/MonitorServicesModule.cs | 8 +- .../Materials/MaterialsModule.cs | 40 +- .../PhysicsParameters/PhysicsParameters.cs | 18 +- .../PrimLimitsModule/PrimLimitsModule.cs | 20 +- .../Properties/AssemblyInfo.cs | 8 +- .../Scripting/JsonStore/JsonStore.cs | 130 +- .../Scripting/JsonStore/JsonStoreCommands.cs | 8 +- .../Scripting/JsonStore/JsonStoreModule.cs | 78 +- .../JsonStore/JsonStoreScriptModule.cs | 102 +- .../Tests/JsonStoreScriptModuleTests.cs | 80 +- .../Interfaces/IAvatarAttachment.cs | 2 +- .../Minimodule/Interfaces/IInventoryItem.cs | 2 +- .../Minimodule/Interfaces/IObject.cs | 16 +- .../Scripting/Minimodule/InventoryItem.cs | 8 +- .../Scripting/Minimodule/MicroScheduler.cs | 2 +- .../Scripting/Minimodule/SOPObject.cs | 28 +- .../Minimodule/SOPObjectInventory.cs | 36 +- .../Scripting/Minimodule/SPAvatar.cs | 8 +- .../Minimodule/SPAvatarAttachment.cs | 6 +- .../Scripting/Minimodule/Test/TestModule.cs | 4 +- .../Scripting/Minimodule/World.cs | 6 +- .../RegionReadyModule/RegionReadyModule.cs | 34 +- .../XmlRpcGridRouterModule.cs | 6 +- .../FreeswitchServiceInConnectorModule.cs | 4 +- .../UserStatistics/Clients_report.cs | 10 +- .../UserStatistics/Default_Report.cs | 18 +- .../UserStatistics/HTMLUtil.cs | 4 +- .../UserStatistics/LogLinesAJAX.cs | 12 +- .../UserStatistics/Prototype_distributor.cs | 2 +- .../UserStatistics/Sessions_Report.cs | 10 +- .../UserStatistics/SimStatsAJAX.cs | 8 +- .../UserStatistics/WebStatsModule.cs | 36 +- .../ViewerSupport/CameraOnlyModeModule.cs | 2 +- .../ViewerSupport/DynamicMenuModule.cs | 4 +- .../ViewerSupport/GodNamesModule.cs | 4 +- .../ViewerSupport/SimulatorFeaturesHelper.cs | 2 +- .../World/AutoBackup/AutoBackupModule.cs | 20 +- .../World/AutoBackup/AutoBackupModuleState.cs | 2 +- .../World/MoneyModule/SampleMoneyModule.cs | 60 +- .../OptionalModules/World/NPC/NPCAvatar.cs | 32 +- .../World/NPC/Tests/NPCModuleTests.cs | 4 +- .../SceneCommands/SceneCommandsModule.cs | 32 +- .../TreePopulator/TreePopulatorModule.cs | 18 +- .../BasicPhysics/BasicPhysicsActor.cs | 16 +- .../BasicPhysics/BasicPhysicsPrim.cs | 16 +- .../PhysicsModules/BulletS/BSAPIUnman.cs | 8 +- .../Region/PhysicsModules/BulletS/BSAPIXNA.cs | 310 +-- .../BulletS/BSActorMoveToTarget.cs | 2 +- .../PhysicsModules/BulletS/BSApiTemplate.cs | 120 +- .../PhysicsModules/BulletS/BSCharacter.cs | 10 +- .../PhysicsModules/BulletS/BSDynamics.cs | 6 +- .../PhysicsModules/BulletS/BSLinkset.cs | 2 +- .../Region/PhysicsModules/BulletS/BSParam.cs | 210 +- .../PhysicsModules/BulletS/BSPhysObject.cs | 6 +- .../Region/PhysicsModules/BulletS/BSPrim.cs | 8 +- .../Region/PhysicsModules/BulletS/BSScene.cs | 10 +- .../PhysicsModules/BulletS/ExtendedPhysics.cs | 2 +- .../BulletS/Properties/AssemblyInfo.cs | 8 +- .../BulletS/Tests/BulletSimTestsUtil.cs | 2 +- .../BulletS/Tests/HullCreation.cs | 2 +- .../ConvexDecompositionDotNet/CTri.cs | 24 +- .../ConvexDecompositionDotNet/Concavity.cs | 10 +- .../ConvexBuilder.cs | 10 +- .../ConvexDecomposition.cs | 10 +- .../ConvexDecompositionDotNet/ConvexResult.cs | 10 +- .../ConvexDecompositionDotNet/HullClasses.cs | 10 +- .../ConvexDecompositionDotNet/HullTriangle.cs | 10 +- .../ConvexDecompositionDotNet/HullUtils.cs | 26 +- .../ConvexDecompositionDotNet/Plane.cs | 10 +- .../ConvexDecompositionDotNet/PlaneTri.cs | 10 +- .../Properties/AssemblyInfo.cs | 10 +- .../ConvexDecompositionDotNet/Quaternion.cs | 16 +- .../ConvexDecompositionDotNet/SplitPlane.cs | 10 +- .../ConvexDecompositionDotNet/VertexLookup.cs | 10 +- .../ConvexDecompositionDotNet/float2.cs | 10 +- .../ConvexDecompositionDotNet/float3.cs | 10 +- .../ConvexDecompositionDotNet/float3x3.cs | 10 +- .../ConvexDecompositionDotNet/float4.cs | 10 +- .../ConvexDecompositionDotNet/float4x4.cs | 168 +- .../ConvexDecompositionDotNet/int3.cs | 10 +- .../ConvexDecompositionDotNet/int4.cs | 10 +- .../Meshing/Meshmerizer/Mesh.cs | 12 +- .../Meshing/Meshmerizer/Meshmerizer.cs | 20 +- .../Meshing/Meshmerizer/PrimMesher.cs | 6 +- .../Meshing/Meshmerizer/SculptMap.cs | 8 +- .../Meshing/Properties/AssemblyInfo.cs | 8 +- OpenSim/Region/PhysicsModules/Ode/ODEApi.cs | 2398 ++++++++--------- .../Region/PhysicsModules/Ode/ODECharacter.cs | 20 +- .../Region/PhysicsModules/Ode/ODEDynamics.cs | 2 +- .../Region/PhysicsModules/Ode/ODEModule.cs | 8 +- OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs | 92 +- .../Ode/ODERayCastRequestManager.cs | 14 +- OpenSim/Region/PhysicsModules/Ode/OdeScene.cs | 78 +- .../Region/PhysicsModules/POS/POSCharacter.cs | 8 +- .../PhysicsModules/SharedBase/IMesher.cs | 2 +- .../SharedBase/NullPhysicsScene.cs | 2 +- .../PhysicsModules/SharedBase/PhysicsActor.cs | 24 +- .../PhysicsModules/SharedBase/PhysicsScene.cs | 14 +- .../SharedBase/PhysicsVector.cs | 2 +- .../SharedBase/VehicleConstants.cs | 2 +- OpenSim/Region/PhysicsModules/ubOde/ODEApi.cs | 2398 ++++++++--------- .../PhysicsModules/ubOde/ODECharacter.cs | 50 +- .../PhysicsModules/ubOde/ODEDynamics.cs | 24 +- .../PhysicsModules/ubOde/ODEMeshWorker.cs | 12 +- .../Region/PhysicsModules/ubOde/ODEModule.cs | 12 +- .../Region/PhysicsModules/ubOde/ODEPrim.cs | 38 +- .../ubOde/ODERayCastRequestManager.cs | 10 +- .../Region/PhysicsModules/ubOde/ODEScene.cs | 64 +- .../PhysicsModules/ubOdeMeshing/Mesh.cs | 6 +- .../ubOdeMeshing/Meshmerizer.cs | 58 +- .../PhysicsModules/ubOdeMeshing/PrimMesher.cs | 18 +- .../ubOdeMeshing/Properties/AssemblyInfo.cs | 8 +- .../PhysicsModules/ubOdeMeshing/SculptMap.cs | 2 +- .../ScriptEngine/Interfaces/ICompiler.cs | 2 +- .../ScriptEngine/Interfaces/IScriptEngine.cs | 4 +- .../Interfaces/IScriptInstance.cs | 6 +- .../Api/Implementation/AsyncCommandManager.cs | 44 +- .../Shared/Api/Implementation/LSL_Api.cs | 118 +- .../Shared/Api/Implementation/LS_Api.cs | 2 +- .../Shared/Api/Implementation/MOD_Api.cs | 74 +- .../Shared/Api/Implementation/OSSL_Api.cs | 106 +- .../Implementation/Plugins/SensorRepeat.cs | 14 +- .../Api/Implementation/Plugins/Timer.cs | 2 +- .../Implementation/Properties/AssemblyInfo.cs | 8 +- .../Shared/Api/Interface/IMOD_Api.cs | 2 +- .../Shared/Api/Interface/IOSSL_Api.cs | 8 +- .../Shared/Api/Runtime/LSL_Constants.cs | 2 +- .../Shared/Api/Runtime/LSL_Stub.cs | 4 +- .../Shared/Api/Runtime/OSSL_Stub.cs | 14 +- .../Api/Runtime/Properties/AssemblyInfo.cs | 8 +- .../Shared/CodeTools/CSCodeGenerator.cs | 26 +- .../Shared/CodeTools/CSReservedWords.cs | 2 +- .../ScriptEngine/Shared/CodeTools/Compiler.cs | 76 +- .../CodeTools/Properties/AssemblyInfo.cs | 8 +- .../Shared/CodeTools/Tests/CompilerTest.cs | 6 +- .../Shared/CodeTools/Tests/LSL_EventTests.cs | 24 +- .../Shared/CodeTools/lsl.lexer.cs | 6 +- .../Shared/CodeTools/lsl.parser.cs | 1710 ++++++------ OpenSim/Region/ScriptEngine/Shared/Helpers.cs | 10 +- .../Instance/Properties/AssemblyInfo.cs | 8 +- .../Shared/Instance/ScriptInstance.cs | 50 +- .../Instance/Tests/CoopTerminationTests.cs | 76 +- .../Region/ScriptEngine/Shared/LSL_Types.cs | 10 +- .../Shared/Properties/AssemblyInfo.cs | 8 +- .../Shared/Tests/LSL_ApiHttpTests.cs | 6 +- .../Shared/Tests/LSL_ApiInventoryTests.cs | 8 +- .../Shared/Tests/LSL_ApiLinkingTests.cs | 4 +- .../Shared/Tests/LSL_ApiListTests.cs | 4 +- .../Shared/Tests/LSL_ApiNotecardTests.cs | 8 +- .../Shared/Tests/LSL_ApiObjectTests.cs | 28 +- .../ScriptEngine/Shared/Tests/LSL_ApiTest.cs | 10 +- .../Shared/Tests/LSL_TypesTestLSLFloat.cs | 2 +- .../Shared/Tests/LSL_TypesTestLSLInteger.cs | 2 +- .../Shared/Tests/LSL_TypesTestLSLString.cs | 2 +- .../Shared/Tests/OSSL_ApiNpcTests.cs | 4 +- .../XEngine/Api/Runtime/XEngineScriptBase.cs | 2 +- .../ScriptEngine/XEngine/EventManager.cs | 4 +- .../XEngine/Properties/AssemblyInfo.cs | 8 +- .../XEngine/Tests/XEngineBasicTests.cs | 2 +- .../XEngine/Tests/XEngineCrossingTests.cs | 14 +- .../Region/ScriptEngine/XEngine/XEngine.cs | 82 +- .../Region/ScriptEngine/XEngine/XWorkItem.cs | 2 +- OpenSim/Server/Base/CommandManager.cs | 88 +- OpenSim/Server/Base/HttpServerBase.cs | 2 +- .../Server/Base/Properties/AssemblyInfo.cs | 8 +- OpenSim/Server/Base/ProtocolVersions.cs | 14 +- OpenSim/Server/Base/ServerUtils.cs | 42 +- OpenSim/Server/Base/ServicesServerBase.cs | 4 +- .../Handlers/Asset/AssetServerConnector.cs | 14 +- .../Handlers/Asset/AssetServerGetHandler.cs | 4 +- .../Tests/AssetServerPostHandlerTests.cs | 12 +- .../AuthenticationServerPostHandler.cs | 20 +- .../Authentication/OpenIdServerConnector.cs | 2 +- .../Authentication/OpenIdServerHandler.cs | 6 +- .../AuthorizationServerPostHandler.cs | 2 +- .../Avatar/AvatarServerPostHandler.cs | 6 +- .../Handlers/BakedTextures/XBakesHandler.cs | 2 +- .../Server/Handlers/Base/ServerConnector.cs | 6 +- .../Server/Handlers/Grid/GridInfoHandlers.cs | 10 +- .../Handlers/Grid/GridServerPostHandler.cs | 10 +- .../Handlers/Hypergrid/AgentHandlers.cs | 2 +- .../Hypergrid/HGFriendServerConnector.cs | 2 +- .../Hypergrid/HGFriendsServerPostHandler.cs | 12 +- .../InstantMessageServerConnector.cs | 2 +- .../Hypergrid/UserAgentServerConnector.cs | 4 +- .../Inventory/InventoryServerInConnector.cs | 6 +- .../Inventory/XInventoryInConnector.cs | 4 +- .../Handlers/Land/LandServiceInConnector.cs | 2 +- .../Server/Handlers/Login/LLLoginHandlers.cs | 8 +- .../Login/LLLoginServiceInConnector.cs | 4 +- .../Handlers/Map/MapAddServerConnector.cs | 2 +- .../Handlers/Map/MapRemoveServerConnector.cs | 2 +- .../Handlers/Neighbour/NeighbourHandlers.cs | 2 +- .../Neighbour/NeighbourServiceInConnector.cs | 2 +- .../Presence/PresenceServerPostHandler.cs | 4 +- .../Profiles/UserProfilesConnector.cs | 6 +- .../Handlers/Profiles/UserProfilesHandlers.cs | 108 +- .../Handlers/Properties/AssemblyInfo.cs | 8 +- .../Handlers/Simulation/AgentHandlers.cs | 10 +- OpenSim/Server/Properties/AssemblyInfo.cs | 8 +- OpenSim/Server/ServerMain.cs | 4 +- OpenSim/Services/AssetService/AssetService.cs | 10 +- .../AssetService/Properties/AssemblyInfo.cs | 8 +- .../Services/AssetService/XAssetService.cs | 10 +- .../AuthenticationServiceBase.cs | 6 +- .../PasswordAuthenticationService.cs | 4 +- .../Properties/AssemblyInfo.cs | 8 +- .../WebkeyAuthenticationService.cs | 6 +- .../WebkeyOrPasswordAuthenticationService.cs | 10 +- .../Properties/AssemblyInfo.cs | 8 +- .../Services/AvatarService/AvatarService.cs | 4 +- .../AvatarService/AvatarServiceBase.cs | 2 +- .../AvatarService/Properties/AssemblyInfo.cs | 8 +- .../Services/Base/Properties/AssemblyInfo.cs | 8 +- OpenSim/Services/Base/ServiceBase.cs | 8 +- .../AgentPreferencesConnector.cs | 2 +- .../Asset/AssetServicesConnector.cs | 22 +- .../AuthorizationServicesConnector.cs | 16 +- .../Avatar/AvatarServicesConnector.cs | 4 +- .../Friends/FriendsServicesConnector.cs | 2 +- .../Connectors/Grid/GridServicesConnector.cs | 4 +- .../Hypergrid/GatekeeperServiceConnector.cs | 2 +- .../Hypergrid/HeloServicesConnector.cs | 2 +- .../Hypergrid/UserAgentServiceConnector.cs | 12 +- .../Inventory/XInventoryServicesConnector.cs | 24 +- .../Connectors/Land/LandServicesConnector.cs | 6 +- .../Presence/PresenceServicesConnector.cs | 8 +- .../Connectors/Properties/AssemblyInfo.cs | 8 +- .../SimianGrid/SimianAssetServiceConnector.cs | 32 +- .../SimianAvatarServiceConnector.cs | 8 +- .../SimianGrid/SimianExternalCapsModule.cs | 16 +- .../Connectors/SimianGrid/SimianGrid.cs | 18 +- .../SimianGrid/SimianGridMaptileModule.cs | 16 +- .../SimianGrid/SimianGridServiceConnector.cs | 8 +- .../SimianInventoryServiceConnector.cs | 8 +- .../SimianPresenceServiceConnector.cs | 10 +- .../Connectors/SimianGrid/SimianProfiles.cs | 6 +- .../SimianUserAccountServiceConnector.cs | 6 +- .../Simulation/SimulationServiceConnector.cs | 24 +- .../UserAccountServicesConnector.cs | 4 +- .../EstateService/EstateDataService.cs | 8 +- .../Services/FSAssetService/FSAssetService.cs | 18 +- .../FreeswitchService/FreeswitchService.cs | 58 +- .../Properties/AssemblyInfo.cs | 8 +- .../Friends/Properties/AssemblyInfo.cs | 8 +- OpenSim/Services/GridService/GridService.cs | 42 +- .../Services/GridService/GridServiceBase.cs | 2 +- .../Services/GridService/HypergridLinker.cs | 16 +- .../GridService/Properties/AssemblyInfo.cs | 8 +- .../HypergridService/GatekeeperService.cs | 20 +- .../HypergridService/HGAssetService.cs | 2 +- .../HypergridService/HGFSAssetService.cs | 2 +- .../HypergridService/HGFriendsService.cs | 2 +- .../HGInstantMessageService.cs | 2 +- .../HypergridService/HGInventoryService.cs | 8 +- .../HypergridService/HGRemoteAssetService.cs | 2 +- .../HGSuitcaseInventoryService.cs | 12 +- .../Properties/AssemblyInfo.cs | 8 +- .../HypergridService/UserAccountCache.cs | 2 +- .../HypergridService/UserAgentService.cs | 22 +- .../Interfaces/IAgentPreferencesService.cs | 2 +- OpenSim/Services/Interfaces/IAssetService.cs | 6 +- .../Interfaces/IAuthenticationService.cs | 2 +- .../Interfaces/IAuthorizationService.cs | 24 +- OpenSim/Services/Interfaces/IAvatarService.cs | 8 +- .../Services/Interfaces/IEstateDataService.cs | 34 +- OpenSim/Services/Interfaces/IGridService.cs | 14 +- .../Services/Interfaces/IGridUserService.cs | 14 +- .../Services/Interfaces/IHypergridServices.cs | 6 +- .../Services/Interfaces/IInventoryService.cs | 6 +- .../Services/Interfaces/IOfflineIMService.cs | 4 +- .../Services/Interfaces/ISimulationService.cs | 2 +- .../Interfaces/IUserProfilesService.cs | 8 +- .../Services/Interfaces/OpenProfileClient.cs | 4 +- .../Interfaces/Properties/AssemblyInfo.cs | 8 +- .../Properties/AssemblyInfo.cs | 8 +- .../Tests/XInventoryServiceTests.cs | 44 +- .../InventoryService/XInventoryService.cs | 38 +- .../LLLoginService/LLLoginResponse.cs | 12 +- .../Services/LLLoginService/LLLoginService.cs | 44 +- .../LLLoginService/Properties/AssemblyInfo.cs | 8 +- .../MapImageService/MapImageService.cs | 6 +- .../Properties/AssemblyInfo.cs | 8 +- .../PresenceService/PresenceService.cs | 8 +- .../PresenceService/PresenceServiceBase.cs | 2 +- .../Properties/AssemblyInfo.cs | 8 +- .../AgentPreferencesService.cs | 2 +- .../UserAccountService/GridUserService.cs | 2 +- .../UserAccountService/GridUserServiceBase.cs | 2 +- .../Properties/AssemblyInfo.cs | 8 +- .../UserAccountService/UserAccountService.cs | 4 +- .../UserProfilesService.cs | 42 +- .../UserProfilesServiceBase.cs | 4 +- OpenSim/Tests/Clients/Grid/GridClient.cs | 8 +- OpenSim/Tests/Common/DatabaseTestAttribute.cs | 6 +- OpenSim/Tests/Common/Helpers/AssetHelpers.cs | 32 +- .../Helpers/BaseRequestHandlerHelpers.cs | 2 +- .../Common/Helpers/ClientStackHelpers.cs | 2 +- .../Common/Helpers/EntityTransferHelpers.cs | 10 +- OpenSim/Tests/Common/Helpers/SceneHelpers.cs | 66 +- .../Common/Helpers/TaskInventoryHelpers.cs | 12 +- .../Common/Helpers/UserAccountHelpers.cs | 4 +- .../Common/Helpers/UserInventoryHelpers.cs | 16 +- OpenSim/Tests/Common/LongRunningAttribute.cs | 4 +- .../Tests/Common/Mock/BaseAssetRepository.cs | 8 +- .../Mock/MockGroupsServicesConnector.cs | 28 +- .../Tests/Common/Mock/MockRegionDataPlugin.cs | 24 +- OpenSim/Tests/Common/Mock/MockScriptEngine.cs | 8 +- OpenSim/Tests/Common/Mock/TestClient.cs | 22 +- .../Common/Mock/TestEventQueueGetModule.cs | 10 +- .../Common/Mock/TestHttpClientContext.cs | 14 +- OpenSim/Tests/Common/Mock/TestHttpRequest.cs | 80 +- OpenSim/Tests/Common/Mock/TestHttpResponse.cs | 36 +- .../Common/Mock/TestInventoryDataPlugin.cs | 40 +- OpenSim/Tests/Common/Mock/TestLLUDPServer.cs | 26 +- OpenSim/Tests/Common/Mock/TestLandChannel.cs | 2 +- OpenSim/Tests/Common/Mock/TestScene.cs | 6 +- .../Common/Mock/TestXInventoryDataPlugin.cs | 10 +- OpenSim/Tests/Common/TestHelpers.cs | 8 +- .../Tests/Robust/Clients/Grid/GridClient.cs | 4 +- .../Clients/Inventory/InventoryClient.cs | 4 +- .../Stress/VectorRenderModuleStressTests.cs | 4 +- OpenSim/Tools/Compiler/Program.cs | 4 +- .../Tools/Compiler/Properties/AssemblyInfo.cs | 8 +- .../Configger/Properties/AssemblyInfo.cs | 8 +- OpenSim/Tools/Configger/Util.cs | 2 +- .../pCampBot/Behaviours/AbstractBehaviour.cs | 4 +- .../pCampBot/Behaviours/CrossBehaviour.cs | 6 +- .../pCampBot/Behaviours/GrabbingBehaviour.cs | 6 +- .../Behaviours/InventoryDownloadBehaviour.cs | 6 +- .../pCampBot/Behaviours/NoneBehaviour.cs | 8 +- .../pCampBot/Behaviours/PhysicsBehaviour2.cs | 6 +- .../pCampBot/Behaviours/TeleportBehaviour.cs | 4 +- .../pCampBot/Behaviours/TwitchyBehaviour.cs | 8 +- OpenSim/Tools/pCampBot/Bot.cs | 24 +- OpenSim/Tools/pCampBot/BotManager.cs | 34 +- .../Tools/pCampBot/Interfaces/IBehaviour.cs | 2 +- .../Tools/pCampBot/Properties/AssemblyInfo.cs | 8 +- OpenSim/Tools/pCampBot/pCampBot.cs | 6 +- .../src/Core/Attributes/DataNodeAttribute.cs | 84 +- .../Core/Attributes/OptionNodeAttribute.cs | 84 +- .../src/Core/Attributes/TargetAttribute.cs | 84 +- Prebuild/src/Core/FatalException.cs | 114 +- Prebuild/src/Core/Interfaces/IDataNode.cs | 52 +- Prebuild/src/Core/Interfaces/ITarget.cs | 62 +- Prebuild/src/Core/Kernel.cs | 1264 ++++----- Prebuild/src/Core/Nodes/AuthorNode.cs | 102 +- Prebuild/src/Core/Nodes/CleanFilesNode.cs | 18 +- Prebuild/src/Core/Nodes/CleanupNode.cs | 74 +- Prebuild/src/Core/Nodes/ConfigurationNode.cs | 330 +-- .../Core/Nodes/ConfigurationNodeCollection.cs | 90 +- Prebuild/src/Core/Nodes/DataNode.cs | 172 +- .../src/Core/Nodes/DatabaseReferenceNode.cs | 6 +- Prebuild/src/Core/Nodes/DescriptionNode.cs | 102 +- Prebuild/src/Core/Nodes/ExcludeNode.cs | 78 +- Prebuild/src/Core/Nodes/FileNode.cs | 440 +-- Prebuild/src/Core/Nodes/FilesNode.cs | 262 +- Prebuild/src/Core/Nodes/MatchNode.cs | 418 +-- Prebuild/src/Core/Nodes/OptionsNode.cs | 1086 ++++---- Prebuild/src/Core/Nodes/ProcessNode.cs | 142 +- Prebuild/src/Core/Nodes/ProjectNode.cs | 946 +++---- Prebuild/src/Core/Nodes/ReferenceNode.cs | 192 +- Prebuild/src/Core/Nodes/ReferencePathNode.cs | 102 +- Prebuild/src/Core/Nodes/SolutionNode.cs | 476 ++-- Prebuild/src/Core/Parse/IfContext.cs | 242 +- Prebuild/src/Core/Parse/Preprocessor.cs | 960 +++---- Prebuild/src/Core/Targets/AutotoolsTarget.cs | 14 +- Prebuild/src/Core/Targets/DebugTarget.cs | 102 +- Prebuild/src/Core/Targets/MakefileTarget.cs | 18 +- .../src/Core/Targets/MonoDevelopTarget.cs | 858 +++--- Prebuild/src/Core/Targets/NAntTarget.cs | 640 ++--- .../src/Core/Targets/SharpDevelop2Target.cs | 88 +- .../src/Core/Targets/SharpDevelopTarget.cs | 692 ++--- Prebuild/src/Core/Targets/ToolInfo.cs | 356 +-- Prebuild/src/Core/Targets/VS2002Target.cs | 114 +- Prebuild/src/Core/Targets/VS2003Target.cs | 1130 ++++---- Prebuild/src/Core/Targets/VS2005Target.cs | 24 +- Prebuild/src/Core/Targets/VS2008Target.cs | 180 +- Prebuild/src/Core/Targets/VS2010Target.cs | 202 +- Prebuild/src/Core/Targets/VSGenericTarget.cs | 1660 ++++++------ Prebuild/src/Core/Targets/VSVersion.cs | 70 +- Prebuild/src/Core/Targets/XcodeTarget.cs | 22 +- Prebuild/src/Core/UnknownLanguageException.cs | 76 +- .../Core/Utilities/CommandLineCollection.cs | 218 +- .../src/Core/Utilities/CurrentDirectory.cs | 80 +- Prebuild/src/Core/Utilities/Helper.cs | 946 +++---- Prebuild/src/Core/Utilities/Log.cs | 434 +-- Prebuild/src/Core/WarningException.cs | 112 +- Prebuild/src/Prebuild.cs | 216 +- Prebuild/src/Properties/AssemblyInfo.cs | 18 +- .../SmartThreadPool/CallerThreadContext.cs | 178 +- ThirdParty/SmartThreadPool/EventWaitHandle.cs | 30 +- .../SmartThreadPool/EventWaitHandleFactory.cs | 6 +- ThirdParty/SmartThreadPool/Interfaces.cs | 420 +-- .../SmartThreadPool/InternalInterfaces.cs | 2 +- ThirdParty/SmartThreadPool/PriorityQueue.cs | 386 +-- .../SmartThreadPool/STPPerformanceCounter.cs | 526 ++-- ThirdParty/SmartThreadPool/STPStartInfo.cs | 148 +- .../SmartThreadPool.ThreadEntry.cs | 6 +- ThirdParty/SmartThreadPool/SmartThreadPool.cs | 1570 +++++------ ThirdParty/SmartThreadPool/WIGStartInfo.cs | 198 +- ThirdParty/SmartThreadPool/WorkItem.cs | 20 +- ThirdParty/SmartThreadPool/WorkItemFactory.cs | 564 ++-- ThirdParty/SmartThreadPool/WorkItemInfo.cs | 104 +- ThirdParty/SmartThreadPool/WorkItemsGroup.cs | 414 +-- .../SmartThreadPool/WorkItemsGroupBase.cs | 14 +- ThirdParty/SmartThreadPool/WorkItemsQueue.cs | 770 +++--- 959 files changed, 23646 insertions(+), 23646 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsExtendedData.cs b/OpenSim/Addons/Groups/GroupsExtendedData.cs index c783b9eeda..d92c4421c7 100644 --- a/OpenSim/Addons/Groups/GroupsExtendedData.cs +++ b/OpenSim/Addons/Groups/GroupsExtendedData.cs @@ -46,7 +46,7 @@ namespace OpenSim.Groups public string AccessToken; } - public class ExtendedGroupMembersData + public class ExtendedGroupMembersData { // This is the only difference: this is a string public string AgentID; @@ -65,7 +65,7 @@ namespace OpenSim.Groups public UUID RoleID; // This is the only difference: this is a string public string MemberID; - + } public struct ExtendedGroupNoticeData diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs index 2ec9652b8a..f4d3490ddc 100644 --- a/OpenSim/Addons/Groups/GroupsMessagingModule.cs +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -131,7 +131,7 @@ namespace OpenSim.Groups { if (!m_groupMessagingEnabled) return; - + scene.RegisterModuleInterface(this); m_sceneList.Add(scene); @@ -163,7 +163,7 @@ namespace OpenSim.Groups if (m_groupData == null) { m_log.Error("[Groups.Messaging]: Could not get IGroupsServicesConnector, GroupsMessagingModule is now disabled."); - RemoveRegion(scene); + RemoveRegion(scene); return; } @@ -218,7 +218,7 @@ namespace OpenSim.Groups m_msgTransferModule = null; } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -262,7 +262,7 @@ namespace OpenSim.Groups { if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); - + GroupRecord groupInfo = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null); if (groupInfo != null) @@ -279,7 +279,7 @@ namespace OpenSim.Groups { SendMessageToGroup(im, groupID, UUID.Zero, null); } - + public void SendMessageToGroup( GridInstantMessage im, UUID groupID, UUID sendingAgentForGroupCalls, Func sendCondition) { @@ -355,9 +355,9 @@ namespace OpenSim.Groups { if (!sendCondition(member)) { - if (m_debugEnabled) + if (m_debugEnabled) m_log.DebugFormat( - "[Groups.Messaging]: Not sending to {0} as they do not fulfill send condition", + "[Groups.Messaging]: Not sending to {0} as they do not fulfill send condition", member.AgentID); continue; @@ -366,7 +366,7 @@ namespace OpenSim.Groups else if (hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID)) { // Don't deliver messages to people who have dropped this session - if (m_debugEnabled) + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} has dropped session, not delivering to them", member.AgentID); continue; @@ -414,7 +414,7 @@ namespace OpenSim.Groups "[Groups.Messaging]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms", groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick); } - + #region SimGridEventHandlers void OnClientLogin(IClientAPI client) @@ -445,13 +445,13 @@ namespace OpenSim.Groups // The instant message module will only deliver messages of dialog types: // MessageFromAgent, StartTyping, StopTyping, MessageFromObject // - // Any other message type will not be delivered to a client by the + // Any other message type will not be delivered to a client by the // Instant Message Module UUID regionID = new UUID(msg.RegionID); if (m_debugEnabled) { - m_log.DebugFormat("[Groups.Messaging]: {0} called, IM from region {1}", + m_log.DebugFormat("[Groups.Messaging]: {0} called, IM from region {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, regionID); DebugGridInstantMessage(msg); @@ -508,7 +508,7 @@ namespace OpenSim.Groups m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he has an agent in region of origin", sp.UUID); return; } - else + else { if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: not skipping agent {0}", sp.UUID); @@ -531,7 +531,7 @@ namespace OpenSim.Groups } } }); - + } } } @@ -555,7 +555,7 @@ namespace OpenSim.Groups break; case (byte)InstantMessageDialog.SessionSend: - // User hasn't dropped, so they're in the session, + // User hasn't dropped, so they're in the session, // maybe we should deliver it. IClientAPI client = GetActiveClient(new UUID(msg.toAgentID)); if (client != null) @@ -655,7 +655,7 @@ namespace OpenSim.Groups UUID AgentID = new UUID(im.fromAgentID); GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null); - + if (groupInfo != null) { AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); @@ -681,7 +681,7 @@ namespace OpenSim.Groups UUID GroupID = new UUID(im.imSessionID); UUID AgentID = new UUID(im.fromAgentID); - if (m_debugEnabled) + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Send message to session for group {0} with session ID {1}", GroupID, im.imSessionID.ToString()); //If this agent is sending a message, then they want to be in the session diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 57fbbf7893..1e9f2b5297 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -51,7 +51,7 @@ namespace OpenSim.Groups private List m_sceneList = new List(); private IMessageTransferModule m_msgTransferModule = null; - + private IGroupsServicesConnector m_groupData = null; private IUserManagement m_UserManagement; @@ -210,7 +210,7 @@ namespace OpenSim.Groups if (m_debugEnabled) m_log.Debug("[Groups]: Shutting down Groups module."); } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -318,7 +318,7 @@ namespace OpenSim.Groups SendAgentGroupDataUpdate(remoteClient, false); - // also current viewers do ignore it and ask later on a much nicer thread + // also current viewers do ignore it and ask later on a much nicer thread // its a info request not a change, so nothing is sent to others // they do get the group title with the avatar object update on arrivel to a region } @@ -453,9 +453,9 @@ namespace OpenSim.Groups } if (m_groupData.AddGroupNotice(GetRequestingAgentIDStr(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, - hasAttachment, + hasAttachment, (byte)(item == null ? 0 : item.AssetType), - item == null ? null : item.Name, + item == null ? null : item.Name, item == null ? UUID.Zero : item.ID, item == null ? UUID.Zero.ToString() : item.Owner.ToString())) { @@ -463,7 +463,7 @@ namespace OpenSim.Groups { OnNewGroupNotice(GroupID, NoticeID); } - + // Send notice out to everyone that wants notices foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), GroupID)) { @@ -497,7 +497,7 @@ namespace OpenSim.Groups m_log.DebugFormat("[Groups]: Giving inventory from {0} to {1}", giver, remoteClient.AgentId); string message; - InventoryItemBase itemCopy = ((Scene)(remoteClient.Scene)).GiveInventoryItem(remoteClient.AgentId, + InventoryItemBase itemCopy = ((Scene)(remoteClient.Scene)).GiveInventoryItem(remoteClient.AgentId, giver, notice.noticeData.AttachmentItemID, out message); if (itemCopy == null) @@ -509,10 +509,10 @@ namespace OpenSim.Groups remoteClient.SendInventoryItemCreateUpdate(itemCopy, 0); } } - + // Interop, received special 210 code for ejecting a group member // this only works within the comms servers domain, and won't work hypergrid - // TODO:FIXME: Use a presense server of some kind to find out where the + // TODO:FIXME: Use a presense server of some kind to find out where the // client actually is, and try contacting that region directly to notify them, // or provide the notification via xmlrpc update queue if ((im.dialog == 210)) @@ -523,7 +523,7 @@ namespace OpenSim.Groups UUID ejecteeID = new UUID(im.toAgentID); - im.imSessionID = UUID.Zero.Guid; + im.imSessionID = UUID.Zero.Guid; im.dialog = (byte)InstantMessageDialog.MessageFromAgent; OutgoingInstantMessage(im, ejecteeID); @@ -577,7 +577,7 @@ namespace OpenSim.Groups { return m_groupData.GetGroupRecord(UUID.Zero.ToString(), UUID.Zero, name); } - + public void ActivateGroup(IClientAPI remoteClient, UUID groupID) { if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); @@ -585,7 +585,7 @@ namespace OpenSim.Groups m_groupData.SetAgentActiveGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID); // Changing active group changes title, active powers, all kinds of things - // anyone who is in any region that can see this client, should probably be + // anyone who is in any region that can see this client, should probably be // updated with new group info. At a minimum, they should get ScenePresence // updated with new title. SendAgentGroupDataUpdate(remoteClient, true); @@ -620,10 +620,10 @@ namespace OpenSim.Groups public List GroupMembersRequest(IClientAPI remoteClient, UUID groupID) { - if (m_debugEnabled) + if (m_debugEnabled) m_log.DebugFormat( "[Groups]: GroupMembersRequest called for {0} from client {1}", groupID, remoteClient.Name); - + List data = m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), groupID); if (m_debugEnabled) @@ -706,7 +706,7 @@ namespace OpenSim.Groups public GroupMembershipData GetMembershipData(UUID groupID, UUID agentID) { - if (m_debugEnabled) + if (m_debugEnabled) m_log.DebugFormat( "[Groups]: {0} called with groupID={1}, agentID={2}", System.Reflection.MethodBase.GetCurrentMethod().Name, groupID, agentID); @@ -776,7 +776,7 @@ namespace OpenSim.Groups } string reason = string.Empty; - UUID groupID = m_groupData.CreateGroup(remoteClient.AgentId, name, charter, showInList, insigniaID, membershipFee, openEnrollment, + UUID groupID = m_groupData.CreateGroup(remoteClient.AgentId, name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, remoteClient.AgentId, out reason); if (groupID != UUID.Zero) @@ -823,7 +823,7 @@ namespace OpenSim.Groups if (membership != null) { return membership.GroupTitle; - } + } return string.Empty; } @@ -839,7 +839,7 @@ namespace OpenSim.Groups // TODO: Not sure what all is needed here, but if the active group role change is for the group // the client currently has set active, then we need to do a scene presence update too // if (m_groupData.GetAgentActiveMembership(GetRequestingAgentID(remoteClient)).GroupID == GroupID) - + SendDataUpdate(remoteClient, true); } @@ -899,7 +899,7 @@ namespace OpenSim.Groups case 1: // Remove m_groupData.RemoveAgentFromGroupRole(GetRequestingAgentIDStr(remoteClient), memberID.ToString(), groupID, roleID); - + break; default: m_log.ErrorFormat("[Groups]: {0} does not understand changes == {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, changes); @@ -1072,7 +1072,7 @@ namespace OpenSim.Groups // Send Message to Ejectee GridInstantMessage msg = new GridInstantMessage(); - + // if local send a normal message if(ejecteeClient != null) { @@ -1324,7 +1324,7 @@ namespace OpenSim.Groups membershipArray = membershipData.ToArray(); } } - + if (m_debugEnabled) { m_log.InfoFormat("[Groups]: Get group membership information for {0} requested by {1}", dataForAgentID, requestingClient.AgentId); diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs index 7d57de190b..98525812e4 100644 --- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -103,7 +103,7 @@ namespace OpenSim.Groups if (!m_Enabled) return; - m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); + m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); scene.RegisterModuleInterface(this); m_Scenes.Add(scene); @@ -135,7 +135,7 @@ namespace OpenSim.Groups { m_LocalGroupsConnector = new GroupsServiceLocalConnectorModule(m_Config, m_UserManagement); // Also, if local, create the endpoint for the HGGroupsService - new HGGroupsServiceRobustConnector(m_Config, MainServer.Instance, string.Empty, + new HGGroupsServiceRobustConnector(m_Config, MainServer.Instance, string.Empty, scene.RequestModuleInterface(), scene.RequestModuleInterface()); } @@ -170,7 +170,7 @@ namespace OpenSim.Groups if (sp is ScenePresence && ((ScenePresence)sp).PresenceType != PresenceType.Npc) { AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); - if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 && + if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 && m_OfflineIM != null && m_Messaging != null) { List ims = m_OfflineIM.GetMessages(aCircuit.AgentID); @@ -184,12 +184,12 @@ namespace OpenSim.Groups #region IGroupsServicesConnector - public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, + public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID, out string reason) { reason = string.Empty; if (m_UserManagement.IsLocalGridUser(RequestingAgentID)) - return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID, + return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason); else { @@ -198,14 +198,14 @@ namespace OpenSim.Groups } } - public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, + public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, out string reason) { reason = string.Empty; string url = string.Empty; string name = string.Empty; if (IsLocal(groupID, out url, out name)) - return m_LocalGroupsConnector.UpdateGroup(AgentUUI(RequestingAgentID), groupID, charter, showInList, insigniaID, membershipFee, + return m_LocalGroupsConnector.UpdateGroup(AgentUUI(RequestingAgentID), groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, out reason); else { @@ -374,7 +374,7 @@ namespace OpenSim.Groups } } - + return new List(); } @@ -626,7 +626,7 @@ namespace OpenSim.Groups } if (agent != null) return Util.ProduceUserUniversalIdentifier(agent); - + // we don't know anything about this foreign user // try asking the user management module, which may know more return m_UserManagement.GetUserUUI(AgentID); @@ -664,7 +664,7 @@ namespace OpenSim.Groups string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; if (Util.ParseUniversalUserIdentifier(uID, out userID, out url, out first, out last, out tmp)) m_UserManagement.AddUser(userID, first, last, url); - + return userID; } diff --git a/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs index f60c1a5f68..af007709be 100644 --- a/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs @@ -64,8 +64,8 @@ namespace OpenSim.Groups m_log.DebugFormat("[Groups.RobustHGConnector]: Starting with config name {0}", m_ConfigName); - string homeURI = Util.GetConfigVarFromSections(config, "HomeURI", - new string[] { "Startup", "Hypergrid", m_ConfigName}, string.Empty); + string homeURI = Util.GetConfigVarFromSections(config, "HomeURI", + new string[] { "Startup", "Hypergrid", m_ConfigName}, string.Empty); if (homeURI == string.Empty) throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide the HomeURI [Startup] or in section {0}", m_ConfigName)); diff --git a/OpenSim/Addons/Groups/IGroupsServicesConnector.cs b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs index a09b59e238..8a6e88dfbf 100644 --- a/OpenSim/Addons/Groups/IGroupsServicesConnector.cs +++ b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs @@ -34,9 +34,9 @@ namespace OpenSim.Groups { public interface IGroupsServicesConnector { - UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, + UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID, out string reason); - bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, + bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, out string reason); ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName); List FindGroups(string RequestingAgentID, string search); @@ -75,7 +75,7 @@ namespace OpenSim.Groups /// If the user is a member of the group then the data structure is returned. If not, then null is returned. /// ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID); - + /// /// Get information about the groups to which a user belongs. /// @@ -87,7 +87,7 @@ namespace OpenSim.Groups /// List GetAgentGroupMemberships(string RequestingAgentID, string AgentID); - bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, + bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID); GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID); List GetGroupNotices(string RequestingAgentID, UUID GroupID); diff --git a/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs index 8e30df5755..c7877c6b9f 100644 --- a/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs +++ b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs @@ -108,7 +108,7 @@ namespace OpenSim.Groups if (!m_Enabled) return; - m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); + m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); scene.RegisterModuleInterface(this); m_Scenes.Add(scene); } @@ -146,16 +146,16 @@ namespace OpenSim.Groups #region IGroupsServicesConnector - public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, + public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID, out string reason) { m_log.DebugFormat("[Groups]: Creating group {0}", name); reason = string.Empty; - return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID, + return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason); } - public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, + public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, out string reason) { reason = string.Empty; @@ -296,7 +296,7 @@ namespace OpenSim.Groups public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) { - return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message, + return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message, hasAttachment, attType, attName, attItemID, attOwnerID); } diff --git a/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs b/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs index 98630eb9a8..e9be9c450d 100644 --- a/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs +++ b/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Mono.Addins; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Addons.Groups")] @@ -15,8 +15,8 @@ using Mono.Addins; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -26,7 +26,7 @@ using Mono.Addins; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs index 7450c1442e..8f6be0d0b5 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs @@ -41,7 +41,7 @@ using Nini.Config; namespace OpenSim.Groups { - public class GroupsServiceRemoteConnector + public class GroupsServiceRemoteConnector { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -71,7 +71,7 @@ namespace OpenSim.Groups } /// - m_log.DebugFormat("[Groups.RemoteConnector]: Groups server at {0}, authentication {1}", + m_log.DebugFormat("[Groups.RemoteConnector]: Groups server at {0}, authentication {1}", m_ServerURI, (m_Auth == null ? "None" : m_Auth.GetType().ToString())); } diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs index d4739c6ac1..b6c75a8c7b 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs @@ -113,7 +113,7 @@ namespace OpenSim.Groups if (!m_Enabled) return; - m_log.DebugFormat("[Groups.RemoteConnector]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); + m_log.DebugFormat("[Groups.RemoteConnector]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); scene.RegisterModuleInterface(this); m_Scenes.Add(scene); } @@ -151,7 +151,7 @@ namespace OpenSim.Groups #region IGroupsServicesConnector - public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, + public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID, out string reason) { m_log.DebugFormat("[Groups.RemoteConnector]: Creating group {0}", name); @@ -167,7 +167,7 @@ namespace OpenSim.Groups return groupID; } - public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, + public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, out string reason) { string r = string.Empty; @@ -186,9 +186,9 @@ namespace OpenSim.Groups if (GroupID == UUID.Zero && (GroupName == null || GroupName != null && GroupName == string.Empty)) return null; - return m_CacheWrapper.GetGroupRecord(RequestingAgentID,GroupID,GroupName, delegate - { - return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName); + return m_CacheWrapper.GetGroupRecord(RequestingAgentID,GroupID,GroupName, delegate + { + return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName); }); } @@ -362,7 +362,7 @@ namespace OpenSim.Groups m_GroupsService.RemoveAgentToGroupInvite(RequestingAgentID, inviteID); } - public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, + public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) { GroupNoticeInfo notice = new GroupNoticeInfo(); diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs index d79e4fa0f0..598e7a5a9d 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs @@ -393,7 +393,7 @@ namespace OpenSim.Groups if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") || !request.ContainsKey("Name") || !request.ContainsKey("Description") || !request.ContainsKey("Title") || - !request.ContainsKey("Powers") || !request.ContainsKey("OP")) + !request.ContainsKey("Powers") || !request.ContainsKey("OP")) NullResult(result, "Bad network data"); else @@ -519,11 +519,11 @@ namespace OpenSim.Groups bool success = false; if (op == "ADD") - success = m_GroupsService.AddAgentToGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), + success = m_GroupsService.AddAgentToGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString())); else if (op == "DELETE") - success = m_GroupsService.RemoveAgentFromGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), + success = m_GroupsService.RemoveAgentFromGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString())); result["RESULT"] = success.ToString(); @@ -647,8 +647,8 @@ namespace OpenSim.Groups string op = request["OP"].ToString(); if (op == "ADD" && request.ContainsKey("GroupID") && request.ContainsKey("RoleID") && request.ContainsKey("AgentID")) - { - bool success = m_GroupsService.AddAgentToGroupInvite(request["RequestingAgentID"].ToString(), + { + bool success = m_GroupsService.AddAgentToGroupInvite(request["RequestingAgentID"].ToString(), new UUID(request["InviteID"].ToString()), new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString()), request["AgentID"].ToString()); @@ -664,7 +664,7 @@ namespace OpenSim.Groups } else if (op == "GET") { - GroupInviteInfo invite = m_GroupsService.GetAgentToGroupInvite(request["RequestingAgentID"].ToString(), + GroupInviteInfo invite = m_GroupsService.GetAgentToGroupInvite(request["RequestingAgentID"].ToString(), new UUID(request["InviteID"].ToString())); if (invite != null) diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs index 710b00a43e..ea0fedd9de 100644 --- a/OpenSim/Addons/Groups/Service/GroupsService.cs +++ b/OpenSim/Addons/Groups/Service/GroupsService.cs @@ -126,7 +126,7 @@ namespace OpenSim.Groups #endregion - public UUID CreateGroup(string RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, + public UUID CreateGroup(string RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID, out string reason) { reason = string.Empty; @@ -264,7 +264,7 @@ namespace OpenSim.Groups if (ownerRole != null) ownerRoleID = ownerRole.RoleID; - // Check visibility? + // Check visibility? // When we don't want to check visibility, we pass it "all" as the requestingAgentID bool checkVisibility = !RequestingAgentID.Equals(UUID.Zero.ToString()); @@ -307,20 +307,20 @@ namespace OpenSim.Groups m.Contribution = Int32.Parse(d.Data["Contribution"]); m.ListInProfile = d.Data["ListInProfile"] == "1" ? true : false; - GridUserData gud = m_GridUserService.Get(d.PrincipalID); - if (gud != null) - { - if (bool.Parse(gud.Data["Online"])) - { - m.OnlineStatus = @"Online"; - } - else - { - int unixtime = int.Parse(gud.Data["Login"]); - // The viewer is very picky about how these strings are formed. Eg. it will crash on malformed dates! - m.OnlineStatus = (unixtime == 0) ? @"unknown" : Util.ToDateTime(unixtime).ToString("MM/dd/yyyy"); - } - } + GridUserData gud = m_GridUserService.Get(d.PrincipalID); + if (gud != null) + { + if (bool.Parse(gud.Data["Online"])) + { + m.OnlineStatus = @"Online"; + } + else + { + int unixtime = int.Parse(gud.Data["Login"]); + // The viewer is very picky about how these strings are formed. Eg. it will crash on malformed dates! + m.OnlineStatus = (unixtime == 0) ? @"unknown" : Util.ToDateTime(unixtime).ToString("MM/dd/yyyy"); + } + } // Is this person an owner of the group? m.IsOwner = (rolemembershipsList.Find(r => r.RoleID == ownerRoleID) != null) ? true : false; @@ -553,8 +553,8 @@ namespace OpenSim.Groups { newRoleID = r.RoleID; break; - } - } + } + } MembershipData member = m_Database.RetrieveMember(GroupID, AgentID); if (member != null) @@ -712,7 +712,7 @@ namespace OpenSim.Groups m_Database.StoreMember(membership); } - public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, + public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) { // Check perms diff --git a/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs b/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs index 8e237aa44b..98d01729c1 100644 --- a/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs +++ b/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs @@ -35,67 +35,67 @@ using OpenSim.Services.Base; namespace OpenSim.Groups { - public class GroupsServiceBase : ServiceBase - { - protected IGroupsData m_Database = null; - protected IGridUserData m_GridUserService = null; + public class GroupsServiceBase : ServiceBase + { + protected IGroupsData m_Database = null; + protected IGridUserData m_GridUserService = null; - public GroupsServiceBase(IConfigSource config, string cName) - : base(config) - { - string dllName = String.Empty; - string connString = String.Empty; - string realm = "os_groups"; - string usersRealm = "GridUser"; - string configName = (cName == string.Empty) ? "Groups" : cName; + public GroupsServiceBase(IConfigSource config, string cName) + : base(config) + { + string dllName = String.Empty; + string connString = String.Empty; + string realm = "os_groups"; + string usersRealm = "GridUser"; + string configName = (cName == string.Empty) ? "Groups" : cName; - // - // Try reading the [DatabaseService] section, if it exists - // - IConfig dbConfig = config.Configs["DatabaseService"]; - if (dbConfig != null) - { - if (dllName == String.Empty) - dllName = dbConfig.GetString("StorageProvider", String.Empty); - if (connString == String.Empty) - connString = dbConfig.GetString("ConnectionString", String.Empty); - } + // + // Try reading the [DatabaseService] section, if it exists + // + IConfig dbConfig = config.Configs["DatabaseService"]; + if (dbConfig != null) + { + if (dllName == String.Empty) + dllName = dbConfig.GetString("StorageProvider", String.Empty); + if (connString == String.Empty) + connString = dbConfig.GetString("ConnectionString", String.Empty); + } - // - // [Groups] section overrides [DatabaseService], if it exists - // - IConfig groupsConfig = config.Configs[configName]; - if (groupsConfig != null) - { - dllName = groupsConfig.GetString("StorageProvider", dllName); - connString = groupsConfig.GetString("ConnectionString", connString); - realm = groupsConfig.GetString("Realm", realm); - } + // + // [Groups] section overrides [DatabaseService], if it exists + // + IConfig groupsConfig = config.Configs[configName]; + if (groupsConfig != null) + { + dllName = groupsConfig.GetString("StorageProvider", dllName); + connString = groupsConfig.GetString("ConnectionString", connString); + realm = groupsConfig.GetString("Realm", realm); + } - // - // We tried, but this doesn't exist. We can't proceed. - // - if (dllName.Equals(String.Empty)) - throw new Exception("No StorageProvider configured"); + // + // We tried, but this doesn't exist. We can't proceed. + // + if (dllName.Equals(String.Empty)) + throw new Exception("No StorageProvider configured"); - m_Database = LoadPlugin(dllName, new Object[] { connString, realm }); - if (m_Database == null) - throw new Exception("Could not find a storage interface in the given module " + dllName); + m_Database = LoadPlugin(dllName, new Object[] { connString, realm }); + if (m_Database == null) + throw new Exception("Could not find a storage interface in the given module " + dllName); - // - // [GridUserService] section overrides [DatabaseService], if it exists - // - IConfig usersConfig = config.Configs["GridUserService"]; - if (usersConfig != null) - { - dllName = usersConfig.GetString("StorageProvider", dllName); - connString = usersConfig.GetString("ConnectionString", connString); + // + // [GridUserService] section overrides [DatabaseService], if it exists + // + IConfig usersConfig = config.Configs["GridUserService"]; + if (usersConfig != null) + { + dllName = usersConfig.GetString("StorageProvider", dllName); + connString = usersConfig.GetString("ConnectionString", connString); usersRealm = usersConfig.GetString("Realm", usersRealm); - } + } - m_GridUserService = LoadPlugin(dllName, new Object[] { connString, usersRealm }); - if (m_GridUserService == null) - throw new Exception("Could not find a storage inferface for the given users module " + dllName); - } - } + m_GridUserService = LoadPlugin(dllName, new Object[] { connString, usersRealm }); + if (m_GridUserService == null) + throw new Exception("Could not find a storage inferface for the given users module " + dllName); + } + } } diff --git a/OpenSim/Addons/Groups/Service/HGGroupsService.cs b/OpenSim/Addons/Groups/Service/HGGroupsService.cs index 56e999bde4..7d86f85186 100644 --- a/OpenSim/Addons/Groups/Service/HGGroupsService.cs +++ b/OpenSim/Addons/Groups/Service/HGGroupsService.cs @@ -76,7 +76,7 @@ namespace OpenSim.Groups // Check if it already exists GroupData grec = m_Database.RetrieveGroup(groupID); - if (grec == null || + if (grec == null || (grec != null && grec.Data["Location"] != string.Empty && grec.Data["Location"].ToLower() != serviceLocation.ToLower())) { // Create the group diff --git a/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs index a980f2215f..fe828bc7ef 100644 --- a/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs +++ b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Mono.Addins; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Addons.OfflineIM")] @@ -15,8 +15,8 @@ using Mono.Addins; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -26,7 +26,7 @@ using Mono.Addins; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs index 047b8becf3..46d497924e 100644 --- a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs +++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs @@ -77,7 +77,7 @@ namespace OpenSim.OfflineIM break; } /// - m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0} with auth {1}", + m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0} with auth {1}", m_ServerURI, (m_Auth == null ? "None" : m_Auth.GetType().ToString())); } @@ -140,7 +140,7 @@ namespace OpenSim.OfflineIM { Dictionary sendData = new Dictionary(); sendData["UserID"] = userID; - + MakeRequest("DELETE", sendData); } diff --git a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs index 02084ffbfe..d1ecdce77b 100644 --- a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs +++ b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs @@ -90,7 +90,7 @@ namespace OpenSim.OfflineIM public bool StoreMessage(GridInstantMessage im, out string reason) { reason = string.Empty; - + // Check limits UUID principalID = new UUID(im.toAgentID); long count = m_Database.GetCount("PrincipalID", principalID.ToString()); diff --git a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs index 89224a64a8..feb73a992c 100644 --- a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs @@ -124,7 +124,7 @@ namespace OpenSim.ApplicationPlugins.LoadRegions m_log.Debug("[LOAD REGIONS PLUGIN]: Creating Region: " + regionsToLoad[i].RegionName + " (ThreadID: " + Thread.CurrentThread.ManagedThreadId.ToString() + ")"); - + bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]); m_openSim.CreateRegion(regionsToLoad[i], true, out scene); diff --git a/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderFileSystem.cs b/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderFileSystem.cs index 1873a0658e..976714c11b 100644 --- a/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderFileSystem.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderFileSystem.cs @@ -38,7 +38,7 @@ namespace OpenSim.ApplicationPlugins.LoadRegions public class RegionLoaderFileSystem : IRegionLoader { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private IConfigSource m_configSource; public void SetIniConfigSource(IConfigSource configSource) @@ -72,11 +72,11 @@ namespace OpenSim.ApplicationPlugins.LoadRegions // Create an empty Regions.ini if there are no existing config files. if (!allowRegionless && configFiles.Length == 0 && iniFiles.Length == 0) - { + { new RegionInfo("DEFAULT REGION CONFIG", Path.Combine(regionConfigPath, "Regions.ini"), false, m_configSource); iniFiles = Directory.GetFiles(regionConfigPath, "*.ini"); } - + m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config files from {0}", regionConfigPath); List regionInfos = new List(); @@ -85,16 +85,16 @@ namespace OpenSim.ApplicationPlugins.LoadRegions foreach (string file in iniFiles) { m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file); - + IConfigSource source = new IniConfigSource(file); foreach (IConfig config in source.Configs) - { + { RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource, config.Name); regionInfos.Add(regionInfo); - + m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName); - + i++; } } @@ -102,12 +102,12 @@ namespace OpenSim.ApplicationPlugins.LoadRegions foreach (string file in configFiles) { m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file); - + RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource); regionInfos.Add(regionInfo); - + m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName); - + i++; } diff --git a/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs b/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs index a8e1f95ed9..a45abad0c6 100644 --- a/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs +++ b/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Mono.Addins; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.ApplicationPlugins.RegionModulesController")] @@ -15,8 +15,8 @@ using Mono.Addins; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -26,7 +26,7 @@ using Mono.Addins; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs b/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs index 8f38a2978b..2e25c60063 100644 --- a/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs +++ b/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs @@ -75,7 +75,7 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController } #region IApplicationPlugin implementation - + public void Initialise (OpenSimBase openSim) { m_openSim = openSim; @@ -111,7 +111,7 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController { m_log.InfoFormat( "[REGIONMODULES]: From plugin {0}, (version {1}), loaded {2} modules, {3} shared, {4} non-shared {5} unknown", - loadedModuleData.Key.Id, + loadedModuleData.Key.Id, loadedModuleData.Key.Version, loadedModuleData.Value[0] + loadedModuleData.Value[1] + loadedModuleData.Value[2], loadedModuleData.Value[0], loadedModuleData.Value[1], loadedModuleData.Value[2]); @@ -261,7 +261,7 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController } #region Region Module interfacesController implementation - + /// /// Check that the given module is no disabled in the [Modules] section of the config files. /// @@ -293,10 +293,10 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController if (className != String.Empty && node.Type.ToString() != className) return false; - } - + } + return true; - } + } // The root of all evil. // This is where we handle adding the modules to scenes when they diff --git a/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs b/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs index c841a694af..590a6a9ce1 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Mono.Addins; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.ApplicationPlugins.RemoteController")] @@ -15,8 +15,8 @@ using Mono.Addins; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -26,7 +26,7 @@ using Mono.Addins; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index 1a7c698eb1..a5c9fb4c48 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -575,7 +575,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } responseData["success"] = true; - + m_log.Info("[RADMIN]: Shutdown Administrator Request complete"); } @@ -747,9 +747,9 @@ namespace OpenSim.ApplicationPlugins.RemoteController { // No INI setting recorded. } - + string regionIniPath; - + if (requestData.Contains("region_file")) { // Make sure that the file to be created is in a subdirectory of the region storage directory. @@ -773,7 +773,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController region.RegionName.Replace(" ", "_").Replace(":", "_"). Replace("/", "_"))); } - + m_log.DebugFormat("[RADMIN] CreateRegion: persisting region {0} to {1}", region.RegionID, regionIniPath); region.SaveRegionToFile("dynamic region", regionIniPath); @@ -782,9 +782,9 @@ namespace OpenSim.ApplicationPlugins.RemoteController { region.Persistent = false; } - + // Set the estate - + // Check for an existing estate List estateIDs = m_application.EstateDataService.GetEstates((string) requestData["estate_name"]); if (estateIDs.Count < 1) @@ -795,12 +795,12 @@ namespace OpenSim.ApplicationPlugins.RemoteController // ok, client wants us to use an explicit UUID // regardless of what the avatar name provided userID = new UUID((string) requestData["estate_owner_uuid"]); - + // Check that the specified user exists Scene currentOrFirst = m_application.SceneManager.CurrentOrFirstScene; IUserAccountService accountService = currentOrFirst.UserAccountService; UserAccount user = accountService.GetUserAccount(currentOrFirst.RegionInfo.ScopeID, userID); - + if (user == null) throw new Exception("Specified user was not found."); } @@ -809,23 +809,23 @@ namespace OpenSim.ApplicationPlugins.RemoteController // We need to look up the UUID for the avatar with the provided name. string ownerFirst = (string) requestData["estate_owner_first"]; string ownerLast = (string) requestData["estate_owner_last"]; - + Scene currentOrFirst = m_application.SceneManager.CurrentOrFirstScene; IUserAccountService accountService = currentOrFirst.UserAccountService; UserAccount user = accountService.GetUserAccount(currentOrFirst.RegionInfo.ScopeID, ownerFirst, ownerLast); - + // Check that the specified user exists if (user == null) throw new Exception("Specified user was not found."); - + userID = user.PrincipalID; } else { throw new Exception("Estate owner details not provided."); } - + // Create a new estate with the name provided region.EstateSettings = m_application.EstateDataService.CreateNewEstate(); @@ -852,7 +852,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController throw new Exception("Failed to join estate."); } } - + // Create the region and perform any initial initialization IScene newScene; @@ -1159,7 +1159,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController // Set home position - GridRegion home = scene.GridService.GetRegionByPosition(scopeID, + GridRegion home = scene.GridService.GetRegionByPosition(scopeID, (int)Util.RegionToWorldLoc(regionXLocation), (int)Util.RegionToWorldLoc(regionYLocation)); if (null == home) { @@ -1389,7 +1389,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController if ((null != regionXLocation) && (null != regionYLocation)) { - GridRegion home = scene.GridService.GetRegionByPosition(scopeID, + GridRegion home = scene.GridService.GetRegionByPosition(scopeID, (int)Util.RegionToWorldLoc((uint)regionXLocation), (int)Util.RegionToWorldLoc((uint)regionYLocation)); if (null == home) { m_log.WarnFormat("[RADMIN]: Unable to set home region for updated user account {0} {1}", firstName, lastName); @@ -1416,7 +1416,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController throw e; } - + m_log.Info("[RADMIN]: UpdateUserAccount: request complete"); } } @@ -1608,7 +1608,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController GetSceneFromRegionParams(requestData, responseData, out scene); string filename = (string) requestData["filename"]; - + bool mergeOar = false; bool skipAssets = false; @@ -1735,7 +1735,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController scene.EventManager.OnOarFileSaved += RemoteAdminOarSaveCompleted; m_log.InfoFormat( - "[RADMIN]: Submitting save OAR request for {0} to file {1}, request ID {2}", + "[RADMIN]: Submitting save OAR request for {0} to file {1}, request ID {2}", scene.Name, filename, requestId); archiver.ArchiveRegion(filename, requestId, options); @@ -2082,8 +2082,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController Hashtable responseData = (Hashtable)response.Value; // Hashtable requestData = (Hashtable)request.Params[0]; - m_application.SceneManager.ForEachScene(s => - s.RegionInfo.EstateSettings = m_application.EstateDataService.LoadEstateSettings(s.RegionInfo.RegionID, false) + m_application.SceneManager.ForEachScene(s => + s.RegionInfo.EstateSettings = m_application.EstateDataService.LoadEstateSettings(s.RegionInfo.RegionID, false) ); responseData["success"] = true; @@ -2815,7 +2815,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController if (destinationFolder.Type != (short)FolderType.Clothing) { destinationFolder = new InventoryFolderBase(); - + destinationFolder.ID = UUID.Random(); destinationFolder.Name = "Clothing"; destinationFolder.Owner = destination; @@ -2951,11 +2951,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController { sourceFolder = new InventoryFolderBase(); sourceFolder.ID = UUID.Random(); - if (assetType == FolderType.Clothing) + if (assetType == FolderType.Clothing) { sourceFolder.Name = "Clothing"; - } - else + } + else { sourceFolder.Name = "Body Parts"; } @@ -3168,7 +3168,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController // Set home position - GridRegion home = scene.GridService.GetRegionByPosition(scopeID, + GridRegion home = scene.GridService.GetRegionByPosition(scopeID, (int)Util.RegionToWorldLoc(regionXLocation), (int)Util.RegionToWorldLoc(regionYLocation)); if (null == home) { m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", names[0], names[1]); diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs index 7ba65c9a76..7492602c46 100644 --- a/OpenSim/Capabilities/Caps.cs +++ b/OpenSim/Capabilities/Caps.cs @@ -64,7 +64,7 @@ namespace OpenSim.Framework.Capabilities private CapsHandlers m_capsHandlers; - private Dictionary m_pollServiceHandlers + private Dictionary m_pollServiceHandlers = new Dictionary(); private Dictionary m_externalCapsHandlers = new Dictionary(); @@ -160,7 +160,7 @@ namespace OpenSim.Framework.Capabilities public void RegisterPollHandler(string capName, PollServiceEventArgs pollServiceHandler) { // m_log.DebugFormat( -// "[CAPS]: Registering handler with name {0}, url {1} for {2}", +// "[CAPS]: Registering handler with name {0}, url {1} for {2}", // capName, pollServiceHandler.Url, m_agentID, m_regionName); m_pollServiceHandlers.Add(capName, pollServiceHandler); @@ -170,7 +170,7 @@ namespace OpenSim.Framework.Capabilities // uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; // string protocol = "http"; // string hostName = m_httpListenerHostName; -// +// // if (MainServer.Instance.UseSSL) // { // hostName = MainServer.Instance.SSLCommonName; @@ -238,7 +238,7 @@ namespace OpenSim.Framework.Capabilities string hostName = m_httpListenerHostName; uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; string protocol = "http"; - + if (MainServer.Instance.UseSSL) { hostName = MainServer.Instance.SSLCommonName; diff --git a/OpenSim/Capabilities/CapsHandlers.cs b/OpenSim/Capabilities/CapsHandlers.cs index 6d3b9b54bf..f5a40dfcae 100644 --- a/OpenSim/Capabilities/CapsHandlers.cs +++ b/OpenSim/Capabilities/CapsHandlers.cs @@ -112,9 +112,9 @@ namespace OpenSim.Framework.Capabilities m_httpListener.RemoveStreamHandler("POST", m_capsHandlers[idx].Path); m_capsHandlers.Remove(idx); } - + if (null == value) return; - + m_capsHandlers[idx] = value; m_httpListener.AddStreamHandler(value); } @@ -147,7 +147,7 @@ namespace OpenSim.Framework.Capabilities { Hashtable caps = new Hashtable(); string protocol = "http://"; - + if (m_useSSL) protocol = "https://"; diff --git a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs index 426174d252..5163169dd9 100644 --- a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs +++ b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs @@ -74,7 +74,7 @@ namespace OpenSim.Capabilities.Handlers int page_size = (string.IsNullOrEmpty(psize) ? 500 : Int32.Parse(psize)); int page_number = (string.IsNullOrEmpty(pnumber) ? 1 : Int32.Parse(pnumber)); - + // Full content request httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; //httpResponse.ContentLength = ??; diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs index e3a9a2213b..53ed1152fd 100644 --- a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs +++ b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs @@ -43,7 +43,7 @@ using Caps = OpenSim.Framework.Capabilities.Caps; namespace OpenSim.Capabilities.Handlers { - public class FetchInvDescHandler + public class FetchInvDescHandler { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -53,14 +53,14 @@ namespace OpenSim.Capabilities.Handlers private IScene m_Scene; // private object m_fetchLock = new Object(); - public FetchInvDescHandler(IInventoryService invService, ILibraryService libService, IScene s) + public FetchInvDescHandler(IInventoryService invService, ILibraryService libService, IScene s) { m_InventoryService = invService; m_LibraryService = libService; m_Scene = s; } - + public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); @@ -72,14 +72,14 @@ namespace OpenSim.Capabilities.Handlers // correctly mark it as a uuid // request = request.Replace("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000"); - + // another hack 1 results in a // System.ArgumentException: Object type System.Int32 cannot // be converted to target type: System.Boolean // request = request.Replace("fetch_folders0", "fetch_folders0"); request = request.Replace("fetch_folders1", "fetch_folders1"); - + Hashtable hash = new Hashtable(); try { @@ -90,9 +90,9 @@ namespace OpenSim.Capabilities.Handlers m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); m_log.Error("Request: " + request); } - + ArrayList foldersrequested = (ArrayList)hash["folders"]; - + string response = ""; string bad_folders_response = ""; @@ -516,7 +516,7 @@ from docs seems this was never a spec // } // } // } -// +// // foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend) // { // m_log.DebugFormat( diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs index 8200a96caf..e239a90dbf 100644 --- a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs +++ b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs @@ -80,7 +80,7 @@ namespace OpenSim.Capabilities.Handlers { // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated m_log.WarnFormat("[FETCH INVENTORY HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); - items = new InventoryItemBase[itemsRequested.Count]; + items = new InventoryItemBase[itemsRequested.Count]; foreach (UUID id in itemIDs) items[i++] = m_inventoryService.GetItem(m_agentID, id); } diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs index 8af3c6485d..94c2c89f45 100644 --- a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs +++ b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs @@ -120,7 +120,7 @@ namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests string request = "itemsitem_id"; request += "10000000-0000-0000-0000-000000000001"; // Notecard 1 request += ""; - + string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp); Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs index 94eef3bb7d..4143aa33af 100644 --- a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs +++ b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs @@ -140,7 +140,7 @@ namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests string request = "foldersfetch_folders1fetch_items1folder_id"; request += m_rootFolderID; request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; - + string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); @@ -203,7 +203,7 @@ namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests // Make sure that the note card link is included Assert.That(llsdresponse.Contains("Link to notecard"), Is.True, "Link to notecard is missing"); - + //Make sure the notecard item itself is included Assert.That(llsdresponse.Contains("Test Notecard 2"), Is.True, "Notecard 2 item (the source) is missing"); diff --git a/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs index 3e01bbb756..41cfdb6bf1 100644 --- a/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs @@ -87,12 +87,12 @@ namespace OpenSim.Capabilities.Handlers OSDMap osdname = new OSDMap(); if(parts[0] == "Unknown") { - osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddHours(1)); + osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddHours(1)); osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddHours(2)); } else { - osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddDays(8)); + osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddDays(8)); osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddMonths(1)); } osdname["display_name"] = OSD.FromString(kvp.Value); diff --git a/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs index 8f70c97880..32da1c2b09 100644 --- a/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs +++ b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs @@ -61,7 +61,7 @@ namespace OpenSim.Capabilities.Handlers if (m_UserManagement == null) throw new Exception(String.Format("Failed to load UserManagement from {0}; config is {1}", umService, m_ConfigName)); - + server.AddStreamHandler( new GetDisplayNamesHandler("/CAPS/agents/", m_UserManagement, "GetDisplayNames", null)); } diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs index 8215124625..062a842748 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs @@ -55,7 +55,7 @@ namespace OpenSim.Capabilities.Handlers private IAssetService m_assetService; public const string DefaultFormat = "x-j2c"; - + public GetTextureHandler(IAssetService assService) { m_assetService = assService; @@ -83,7 +83,7 @@ namespace OpenSim.Capabilities.Handlers if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) { // m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID); - + string[] formats; if (!string.IsNullOrEmpty(format)) { @@ -129,7 +129,7 @@ namespace OpenSim.Capabilities.Handlers } /// - /// + /// /// /// /// @@ -190,7 +190,7 @@ namespace OpenSim.Capabilities.Handlers //response = new Hashtable(); - + //WriteTextureData(request,response,null,format); // not found //m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); @@ -287,7 +287,7 @@ namespace OpenSim.Capabilities.Handlers response["content_type"] = texture.Metadata.ContentType; else response["content_type"] = "image/" + format; - + response["bin_response_data"] = texture.Data; response["int_bytes"] = texture.Data.Length; @@ -400,7 +400,7 @@ namespace OpenSim.Capabilities.Handlers if (image != null) image.Dispose(); - + if(managedImage != null) managedImage.Clear(); if (imgstream != null) diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs index 5f86ed4dbf..d5df7a29bd 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs @@ -24,7 +24,7 @@ * (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; using System.Collections.Specialized; @@ -44,7 +44,7 @@ using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Interfaces; using OpenSim.Services.Interfaces; using Caps = OpenSim.Framework.Capabilities.Caps; - + namespace OpenSim.Capabilities.Handlers { public class GetTextureRobustHandler : BaseStreamHandler @@ -52,9 +52,9 @@ namespace OpenSim.Capabilities.Handlers private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IAssetService m_assetService; - + public const string DefaultFormat = "x-j2c"; - + // TODO: Change this to a config option private string m_RedirectURL = null; @@ -66,28 +66,28 @@ namespace OpenSim.Capabilities.Handlers if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/")) m_RedirectURL += "/"; } - + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // Try to parse the texture ID from the request URL NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); string textureStr = query.GetOne("texture_id"); string format = query.GetOne("format"); - + //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr); - + if (m_assetService == null) { m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; return null; } - + UUID textureID; if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) { // m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID); - + string[] formats; if (!string.IsNullOrEmpty(format)) { @@ -98,10 +98,10 @@ namespace OpenSim.Capabilities.Handlers formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); if (formats.Length == 0) formats = new string[1] { DefaultFormat }; // default - + } // OK, we have an array with preferred formats, possibly with only one entry - + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; foreach (string f in formats) { @@ -113,14 +113,14 @@ namespace OpenSim.Capabilities.Handlers { m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); } - + // m_log.DebugFormat( // "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", // textureID, httpResponse.StatusCode, httpResponse.ContentLength); - + return null; } - + /// /// /// @@ -133,16 +133,16 @@ namespace OpenSim.Capabilities.Handlers { // m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); AssetBase texture; - + string fullID = textureID.ToString(); if (format != DefaultFormat) fullID = fullID + "-" + format; - + if (!String.IsNullOrEmpty(m_RedirectURL)) { // Only try to fetch locally cached textures. Misses are redirected texture = m_assetService.GetCached(fullID); - + if (texture != null) { if (texture.Type != (sbyte)AssetType.Texture) @@ -166,14 +166,14 @@ namespace OpenSim.Capabilities.Handlers { // try the cache texture = m_assetService.GetCached(fullID); - + if (texture == null) { // m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache"); - + // Fetch locally or remotely. Misses return a 404 texture = m_assetService.Get(textureID.ToString()); - + if (texture != null) { if (texture.Type != (sbyte)AssetType.Texture) @@ -192,7 +192,7 @@ namespace OpenSim.Capabilities.Handlers newTexture.Data = ConvertTextureData(texture, format); if (newTexture.Data.Length == 0) return false; // !!! Caller try another codec, please! - + newTexture.Flags = AssetFlags.Collectable; newTexture.Temporary = true; newTexture.Local = true; @@ -209,17 +209,17 @@ namespace OpenSim.Capabilities.Handlers return true; } } - + // not found // m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; return true; } - + private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) { string range = request.Headers.GetOne("Range"); - + if (!String.IsNullOrEmpty(range)) // JP2's only { // Range request @@ -233,7 +233,7 @@ namespace OpenSim.Capabilities.Handlers // m_log.DebugFormat( // "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}", // texture.ID, start, texture.Data.Length); - + // Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back // Requested Range Not Satisfiable (416) here. However, it appears that at least recent implementations // of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously @@ -244,7 +244,7 @@ namespace OpenSim.Capabilities.Handlers // level 2. If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable // here will cause the viewer to treat the texture as bad and never display the full resolution // However, if we return PartialContent (or OK) instead, the viewer will display that resolution. - + // response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; // response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length)); // response.StatusCode = (int)System.Net.HttpStatusCode.OK; @@ -257,13 +257,13 @@ namespace OpenSim.Capabilities.Handlers // the rest of the entity. if (end == -1) end = int.MaxValue; - + end = Utils.Clamp(end, 0, texture.Data.Length - 1); start = Utils.Clamp(start, 0, end); int len = end - start + 1; - + // m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); - + // Always return PartialContent, even if the range covered the entire data length // We were accidentally sending back 404 before in this situation // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the @@ -275,11 +275,11 @@ namespace OpenSim.Capabilities.Handlers // response.StatusCode = (int)System.Net.HttpStatusCode.OK; // else response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; - + response.ContentLength = len; response.ContentType = texture.Metadata.ContentType; response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); - + response.Body.Write(texture.Data, start, len); } } @@ -300,7 +300,7 @@ namespace OpenSim.Capabilities.Handlers response.ContentType = "image/" + format; response.Body.Write(texture.Data, 0, texture.Data.Length); } - + // if (response.StatusCode < 200 || response.StatusCode > 299) // m_log.WarnFormat( // "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})", @@ -310,7 +310,7 @@ namespace OpenSim.Capabilities.Handlers // "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})", // texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length); } - + /// /// Parse a range header. /// @@ -327,18 +327,18 @@ namespace OpenSim.Capabilities.Handlers private bool TryParseRange(string header, out int start, out int end) { start = end = 0; - + if (header.StartsWith("bytes=")) { string[] rangeValues = header.Substring(6).Split('-'); - + if (rangeValues.Length == 2) { if (!Int32.TryParse(rangeValues[0], out start)) return false; - + string rawEnd = rangeValues[1]; - + if (rawEnd == "") { end = -1; @@ -350,27 +350,27 @@ namespace OpenSim.Capabilities.Handlers } } } - + start = end = 0; return false; } - + private byte[] ConvertTextureData(AssetBase texture, string format) { m_log.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format); byte[] data = new byte[0]; - + MemoryStream imgstream = new MemoryStream(); Bitmap mTexture = null; ManagedImage managedImage = null; Image image = null; - + try { // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data - + imgstream = new MemoryStream(); - + // Decode image to System.Drawing.Image if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image) && image != null) { @@ -380,7 +380,7 @@ namespace OpenSim.Capabilities.Handlers using(EncoderParameters myEncoderParameters = new EncoderParameters()) { myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,95L); - + // Save bitmap to stream ImageCodecInfo codec = GetEncoderInfo("image/" + format); if (codec != null) @@ -404,10 +404,10 @@ namespace OpenSim.Capabilities.Handlers // If we encountered an exception, one or more of these will be null if (mTexture != null) mTexture.Dispose(); - + if (image != null) image.Dispose(); - + if(managedImage != null) managedImage.Clear(); @@ -417,10 +417,10 @@ namespace OpenSim.Capabilities.Handlers imgstream.Dispose(); } } - + return data; } - + // From msdn private static ImageCodecInfo GetEncoderInfo(String mimeType) { diff --git a/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs b/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs index f628ac1251..387b3de9dd 100644 --- a/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs +++ b/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Capabilities.Handlers")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,7 +25,7 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs index 5536564233..80b83069e2 100644 --- a/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs +++ b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs @@ -51,7 +51,7 @@ namespace OpenSim.Capabilities.Handlers { public class UploadBakedTextureHandler { - + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Caps m_HostCapsObj; @@ -81,7 +81,7 @@ namespace OpenSim.Capabilities.Handlers { string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); - + BakedTextureUploader uploader = new BakedTextureUploader(capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_HostCapsObj.AgentID); uploader.OnUpLoad += BakedTextureUploaded; @@ -127,7 +127,7 @@ namespace OpenSim.Capabilities.Handlers asset.Temporary = true; asset.Local = !m_persistBakedTextures; // Local assets aren't persisted, non-local are m_assetService.Store(asset); - + } } @@ -151,7 +151,7 @@ namespace OpenSim.Capabilities.Handlers // m_log.InfoFormat("[CAPS] baked texture upload starting for {0}",newAssetID); } - + /// /// Handle raw uploaded baked texture data. diff --git a/OpenSim/Capabilities/LLSDAssetUploadResponse.cs b/OpenSim/Capabilities/LLSDAssetUploadResponse.cs index 7c4bc97476..97491e33b6 100644 --- a/OpenSim/Capabilities/LLSDAssetUploadResponse.cs +++ b/OpenSim/Capabilities/LLSDAssetUploadResponse.cs @@ -78,7 +78,7 @@ namespace OpenSim.Framework.Capabilities public string state; public int upload_price; public string rsvp; - + public LLSDNewFileAngentInventoryVariablePriceReplyResponse() { state = "confirm_upload"; diff --git a/OpenSim/Capabilities/LLSDAvatarPicker.cs b/OpenSim/Capabilities/LLSDAvatarPicker.cs index d0b3f3a5ec..12e892c9de 100644 --- a/OpenSim/Capabilities/LLSDAvatarPicker.cs +++ b/OpenSim/Capabilities/LLSDAvatarPicker.cs @@ -42,7 +42,7 @@ namespace OpenSim.Framework.Capabilities { public string username; public string display_name; - //'display_name_next_update':d"1970-01-01T00:00:00Z" + //'display_name_next_update':d"1970-01-01T00:00:00Z" public string legacy_first_name; public string legacy_last_name; public UUID id; diff --git a/OpenSim/Capabilities/LLSDInventoryItem.cs b/OpenSim/Capabilities/LLSDInventoryItem.cs index 958e8079b4..460a2155ed 100644 --- a/OpenSim/Capabilities/LLSDInventoryItem.cs +++ b/OpenSim/Capabilities/LLSDInventoryItem.cs @@ -87,12 +87,12 @@ namespace OpenSim.Framework.Capabilities [OSDMap] public class LLSDInventoryFolderContents { - public UUID agent_id; + public UUID agent_id; public int descendents; - public UUID folder_id; + public UUID folder_id; public OSDArray categories = new OSDArray(); public OSDArray items = new OSDArray(); - public UUID owner_id; + public UUID owner_id; public int version; } diff --git a/OpenSim/Capabilities/Properties/AssemblyInfo.cs b/OpenSim/Capabilities/Properties/AssemblyInfo.cs index f8a9daeac0..72a52409ad 100644 --- a/OpenSim/Capabilities/Properties/AssemblyInfo.cs +++ b/OpenSim/Capabilities/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Capabilities")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,7 +25,7 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/ConsoleClient/ConsoleClient.cs b/OpenSim/ConsoleClient/ConsoleClient.cs index 7c003eaf81..e689424d7d 100644 --- a/OpenSim/ConsoleClient/ConsoleClient.cs +++ b/OpenSim/ConsoleClient/ConsoleClient.cs @@ -178,7 +178,7 @@ namespace OpenSim.ConsoleClient Requester.MakeRequest(requestUrl, requestData, ReadResponses); return; } - + List lines = new List(); foreach (XmlNode part in rootNodeL[0].ChildNodes) @@ -202,7 +202,7 @@ namespace OpenSim.ConsoleClient string[] parts = l.Split(new char[] {':'}, 3); if (parts.Length != 3) continue; - + if (parts[2].StartsWith("+++") || parts[2].StartsWith("-++")) prompt = parts[2]; else diff --git a/OpenSim/ConsoleClient/Properties/AssemblyInfo.cs b/OpenSim/ConsoleClient/Properties/AssemblyInfo.cs index 9c0c784838..87bff142d5 100644 --- a/OpenSim/ConsoleClient/Properties/AssemblyInfo.cs +++ b/OpenSim/ConsoleClient/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.ConsoleClient")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,7 +25,7 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/Data/DBGuids.cs b/OpenSim/Data/DBGuids.cs index ad1c19c6ee..1a2bf4169f 100644 --- a/OpenSim/Data/DBGuids.cs +++ b/OpenSim/Data/DBGuids.cs @@ -38,7 +38,7 @@ namespace OpenSim.Data /// This function converts a value returned from the database in one of the /// supported formats into a UUID. This function is not actually DBMS-specific right /// now - /// + /// /// /// /// diff --git a/OpenSim/Data/IAvatarData.cs b/OpenSim/Data/IAvatarData.cs index 0a18e211f4..b3f12c17a4 100644 --- a/OpenSim/Data/IAvatarData.cs +++ b/OpenSim/Data/IAvatarData.cs @@ -39,7 +39,7 @@ namespace OpenSim.Data public Dictionary Data; } - public interface IAvatarData + public interface IAvatarData { AvatarBaseData[] Get(string field, string val); bool Store(AvatarBaseData data); diff --git a/OpenSim/Data/IEstateDataStore.cs b/OpenSim/Data/IEstateDataStore.cs index f9070eaf2f..6b30db2295 100644 --- a/OpenSim/Data/IEstateDataStore.cs +++ b/OpenSim/Data/IEstateDataStore.cs @@ -46,14 +46,14 @@ namespace OpenSim.Data /// If true, then an estate is created if one is not found. /// EstateSettings LoadEstateSettings(UUID regionID, bool create); - + /// /// Load estate settings for an estate ID. /// /// /// EstateSettings LoadEstateSettings(int estateID); - + /// /// Create a new estate. /// @@ -67,7 +67,7 @@ namespace OpenSim.Data /// /// An empty list if no estates were found. List LoadEstateSettingsAll(); - + /// /// Store estate settings. /// @@ -75,7 +75,7 @@ namespace OpenSim.Data /// This is also called by EstateSettings.Save() /// void StoreEstateSettings(EstateSettings es); - + /// /// Get estate IDs. /// @@ -88,13 +88,13 @@ namespace OpenSim.Data /// /// An empty list if no estates were found. List GetEstatesByOwner(UUID ownerID); - + /// /// Get the IDs of all estates. /// /// An empty list if no estates were found. List GetEstatesAll(); - + /// /// Link a region to an estate. /// @@ -102,14 +102,14 @@ namespace OpenSim.Data /// /// true if the link succeeded, false otherwise bool LinkRegion(UUID regionID, int estateID); - + /// /// Get the UUIDs of all the regions in an estate. /// /// /// List GetRegions(int estateID); - + /// /// Delete an estate /// diff --git a/OpenSim/Data/IGridUserData.cs b/OpenSim/Data/IGridUserData.cs index 9afa477f30..1b2ea87e80 100644 --- a/OpenSim/Data/IGridUserData.cs +++ b/OpenSim/Data/IGridUserData.cs @@ -47,7 +47,7 @@ namespace OpenSim.Data /// /// An interface for connecting to the user grid datastore /// - public interface IGridUserData + public interface IGridUserData { GridUserData Get(string userID); GridUserData[] GetAll(string query); diff --git a/OpenSim/Data/IGroupsData.cs b/OpenSim/Data/IGroupsData.cs index c11e6499a5..bd059e0894 100644 --- a/OpenSim/Data/IGroupsData.cs +++ b/OpenSim/Data/IGroupsData.cs @@ -81,7 +81,7 @@ namespace OpenSim.Data } - public interface IGroupsData + public interface IGroupsData { // groups table bool StoreGroup(GroupData data); diff --git a/OpenSim/Data/IHGTravelingData.cs b/OpenSim/Data/IHGTravelingData.cs index 452af7bc50..5e4894ebf0 100644 --- a/OpenSim/Data/IHGTravelingData.cs +++ b/OpenSim/Data/IHGTravelingData.cs @@ -48,7 +48,7 @@ namespace OpenSim.Data /// /// An interface for connecting to the user grid datastore /// - public interface IHGTravelingData + public interface IHGTravelingData { HGTravelingData Get(UUID sessionID); HGTravelingData[] GetSessions(UUID userID); diff --git a/OpenSim/Data/IOfflineIMData.cs b/OpenSim/Data/IOfflineIMData.cs index 58501a3b7d..a0f4d694ef 100644 --- a/OpenSim/Data/IOfflineIMData.cs +++ b/OpenSim/Data/IOfflineIMData.cs @@ -39,7 +39,7 @@ namespace OpenSim.Data } - public interface IOfflineIMData + public interface IOfflineIMData { OfflineIMData[] Get(string field, string val); long GetCount(string field, string key); diff --git a/OpenSim/Data/IPresenceData.cs b/OpenSim/Data/IPresenceData.cs index 9ec48b0e2a..408624511b 100644 --- a/OpenSim/Data/IPresenceData.cs +++ b/OpenSim/Data/IPresenceData.cs @@ -44,7 +44,7 @@ namespace OpenSim.Data /// /// An interface for connecting to the presence datastore /// - public interface IPresenceData + public interface IPresenceData { bool Store(PresenceData data); diff --git a/OpenSim/Data/IRegionData.cs b/OpenSim/Data/IRegionData.cs index ca9b32716c..c8e38a49ce 100644 --- a/OpenSim/Data/IRegionData.cs +++ b/OpenSim/Data/IRegionData.cs @@ -67,7 +67,7 @@ namespace OpenSim.Data /// /// An interface for connecting to the authentication datastore /// - public interface IRegionData + public interface IRegionData { RegionData Get(UUID regionID, UUID ScopeID); List Get(string regionName, UUID ScopeID); diff --git a/OpenSim/Data/IXGroupData.cs b/OpenSim/Data/IXGroupData.cs index e5821ef2dc..82073fe80d 100644 --- a/OpenSim/Data/IXGroupData.cs +++ b/OpenSim/Data/IXGroupData.cs @@ -38,12 +38,12 @@ namespace OpenSim.Data public UUID ownerRoleID; public string name; public string charter; - public bool showInList; - public UUID insigniaID; + public bool showInList; + public UUID insigniaID; public int membershipFee; public bool openEnrollment; public bool allowPublish; - public bool maturePublish; + public bool maturePublish; public UUID founderID; public ulong everyonePowers; public ulong ownersPowers; diff --git a/OpenSim/Data/Migration.cs b/OpenSim/Data/Migration.cs index d60647015f..e54bf55a7b 100644 --- a/OpenSim/Data/Migration.cs +++ b/OpenSim/Data/Migration.cs @@ -80,10 +80,10 @@ namespace OpenSim.Data /// Have the parameterless constructor just so we can specify it as a generic parameter with the new() constraint. /// Currently this is only used in the tests. A Migration instance created this way must be then - /// initialized with Initialize(). Regular creation should be through the parameterized constructors. + /// initialized with Initialize(). Regular creation should be through the parameterized constructors. /// public Migration() - { + { } public Migration(DbConnection conn, Assembly assem, string subtype, string type) @@ -91,7 +91,7 @@ namespace OpenSim.Data Initialize(conn, assem, type, subtype); } - public Migration(DbConnection conn, Assembly assem, string type) + public Migration(DbConnection conn, Assembly assem, string type) { Initialize(conn, assem, type, ""); } @@ -191,7 +191,7 @@ namespace OpenSim.Data int newversion = kvp.Key; // we need to up the command timeout to infinite as we might be doing long migrations. - /* [AlexRa 01-May-10]: We can't always just run any SQL in a single batch (= ExecuteNonQuery()). Things like + /* [AlexRa 01-May-10]: We can't always just run any SQL in a single batch (= ExecuteNonQuery()). Things like * stored proc definitions might have to be sent to the server each in a separate batch. * This is certainly so for MS SQL; not sure how the MySQL connector sorts out the mess * with 'delimiter @@'/'delimiter ;' around procs. So each "script" this code executes now is not @@ -276,7 +276,7 @@ namespace OpenSim.Data private delegate void FlushProc(); /// Scans for migration resources in either old-style "scattered" (one file per version) - /// or new-style "integrated" format (single file with ":VERSION nnn" sections). + /// or new-style "integrated" format (single file with ":VERSION nnn" sections). /// In the new-style migrations it also recognizes ':GO' separators for parts of the SQL script /// that must be sent to the server separately. The old-style migrations are loaded each in one piece /// and don't support the ':GO' feature. @@ -301,12 +301,12 @@ namespace OpenSim.Data { /* The filename should be '.migrations[.NNN]' where NNN * is the last version number defined in the file. If the '.NNN' part is recognized, the code can skip - * the file without looking inside if we have a higher version already. Without the suffix we read + * the file without looking inside if we have a higher version already. Without the suffix we read * the file anyway and use the version numbers inside. Any unrecognized suffix (such as '.sql') * is valid but ignored. - * - * NOTE that we expect only one 'merged' migration file. If there are several, we take the last one. - * If you are numbering them, leave only the latest one in the project or at least make sure they numbered + * + * NOTE that we expect only one 'merged' migration file. If there are several, we take the last one. + * If you are numbering them, leave only the latest one in the project or at least make sure they numbered * to come up in the correct order (e.g. 'SomeStore.migrations.001' rather than 'SomeStore.migrations.1') */ @@ -351,7 +351,7 @@ namespace OpenSim.Data if (sLine.Trim().Equals(":GO", StringComparison.InvariantCultureIgnoreCase)) { if (sb.Length == 0) continue; - if (nVersion > after) + if (nVersion > after) script.Add(sb.ToString()); sb.Length = 0; continue; @@ -405,10 +405,10 @@ scan_old_style: } } } - - if (migrations.Count < 1) + + if (migrations.Count < 1) m_log.DebugFormat("[MIGRATIONS]: {0} data tables already up to date at revision {1}", _type, after); - + return migrations; } } diff --git a/OpenSim/Data/MySQL/MySQLAssetData.cs b/OpenSim/Data/MySQL/MySQLAssetData.cs index 1488e1a5bb..f16cd913e7 100644 --- a/OpenSim/Data/MySQL/MySQLAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLAssetData.cs @@ -329,8 +329,8 @@ namespace OpenSim.Data.MySQL { m_log.Error( string.Format( - "[ASSETS DB]: MySql failure fetching asset set from {0}, count {1}. Exception ", - start, count), + "[ASSETS DB]: MySql failure fetching asset set from {0}, count {1}. Exception ", + start, count), e); } } diff --git a/OpenSim/Data/MySQL/MySQLAuthenticationData.cs b/OpenSim/Data/MySQL/MySQLAuthenticationData.cs index 76274972a8..af6be75bf7 100644 --- a/OpenSim/Data/MySQL/MySQLAuthenticationData.cs +++ b/OpenSim/Data/MySQL/MySQLAuthenticationData.cs @@ -77,21 +77,21 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("?principalID", principalID.ToString()); IDataReader result = cmd.ExecuteReader(); - + if (result.Read()) { ret.PrincipalID = principalID; - + CheckColumnNames(result); - + foreach (string s in m_ColumnNames) { if (s == "UUID") continue; - + ret.Data[s] = result[s].ToString(); } - + return ret; } else @@ -132,25 +132,25 @@ namespace OpenSim.Data.MySQL if (!first) update += ", "; update += "`" + field + "` = ?"+field; - + first = false; - + cmd.Parameters.AddWithValue("?"+field, data.Data[field]); } - + update += " where UUID = ?principalID"; - + cmd.CommandText = update; cmd.Parameters.AddWithValue("?principalID", data.PrincipalID.ToString()); - + if (ExecuteNonQuery(cmd) < 1) { string insert = "insert into `" + m_Realm + "` (`UUID`, `" + String.Join("`, `", fields) + "`) values (?principalID, ?" + String.Join(", ?", fields) + ")"; - + cmd.CommandText = insert; - + if (ExecuteNonQuery(cmd) < 1) return false; } @@ -166,7 +166,7 @@ namespace OpenSim.Data.MySQL { cmd.Parameters.AddWithValue("?"+item, value); cmd.Parameters.AddWithValue("?UUID", principalID.ToString()); - + if (ExecuteNonQuery(cmd) > 0) return true; } @@ -186,7 +186,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("?principalID", principalID.ToString()); cmd.Parameters.AddWithValue("?token", token); cmd.Parameters.AddWithValue("?lifetime", lifetime.ToString()); - + if (ExecuteNonQuery(cmd) > 0) return true; } diff --git a/OpenSim/Data/MySQL/MySQLAvatarData.cs b/OpenSim/Data/MySQL/MySQLAvatarData.cs index 6a2f5d814d..63e80209b4 100644 --- a/OpenSim/Data/MySQL/MySQLAvatarData.cs +++ b/OpenSim/Data/MySQL/MySQLAvatarData.cs @@ -57,7 +57,7 @@ namespace OpenSim.Data.MySQL cmd.CommandText = String.Format("delete from {0} where `PrincipalID` = ?PrincipalID and `Name` = ?Name", m_Realm); cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString()); cmd.Parameters.AddWithValue("?Name", name); - + if (ExecuteNonQuery(cmd) > 0) return true; } diff --git a/OpenSim/Data/MySQL/MySQLEstateData.cs b/OpenSim/Data/MySQL/MySQLEstateData.cs index fe1487bba8..a5c8d24de5 100644 --- a/OpenSim/Data/MySQL/MySQLEstateData.cs +++ b/OpenSim/Data/MySQL/MySQLEstateData.cs @@ -403,19 +403,19 @@ namespace OpenSim.Data.MySQL return e; } } - + public List LoadEstateSettingsAll() { - List allEstateSettings = new List(); - + List allEstateSettings = new List(); + List allEstateIds = GetEstatesAll(); - + foreach (int estateId in allEstateIds) allEstateSettings.Add(LoadEstateSettings(estateId)); - + return allEstateSettings; } - + public List GetEstatesAll() { List result = new List(); @@ -441,7 +441,7 @@ namespace OpenSim.Data.MySQL dbcon.Close(); } - return result; + return result; } public List GetEstates(string search) diff --git a/OpenSim/Data/MySQL/MySQLFSAssetData.cs b/OpenSim/Data/MySQL/MySQLFSAssetData.cs index 4ed2de688e..2837ce31be 100644 --- a/OpenSim/Data/MySQL/MySQLFSAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLFSAssetData.cs @@ -54,7 +54,7 @@ namespace OpenSim.Data.MySQL { get { return GetType().Assembly; } } - + public MySQLFSAssetData() { } diff --git a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs index dc657c82a8..6aae9c644b 100644 --- a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs +++ b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs @@ -40,7 +40,7 @@ namespace OpenSim.Data.MySQL public class MySQLGenericTableHandler : MySqlFramework where T: class, new() { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + protected Dictionary m_Fields = new Dictionary(); @@ -58,7 +58,7 @@ namespace OpenSim.Data.MySQL { m_Realm = realm; m_connectionString = connectionString; - + if (storeName != String.Empty) { using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) @@ -130,7 +130,7 @@ namespace OpenSim.Data.MySQL m_Realm, where); cmd.CommandText = query; - + return DoQuery(cmd); } } @@ -185,7 +185,7 @@ namespace OpenSim.Data.MySQL m_Fields[name].SetValue(row, reader[name]); } } - + if (m_DataField != null) { Dictionary data = @@ -215,9 +215,9 @@ namespace OpenSim.Data.MySQL { string query = String.Format("select * from {0} where {1}", m_Realm, where); - + cmd.CommandText = query; - + return DoQuery(cmd); } } @@ -236,16 +236,16 @@ namespace OpenSim.Data.MySQL { names.Add(fi.Name); values.Add("?" + fi.Name); - + // Temporarily return more information about what field is unexpectedly null for - // http://opensimulator.org/mantis/view.php?id=5403. This might be due to a bug in the + // http://opensimulator.org/mantis/view.php?id=5403. This might be due to a bug in the // InventoryTransferModule or we may be required to substitute a DBNull here. if (fi.GetValue(row) == null) throw new NullReferenceException( string.Format( - "[MYSQL GENERIC TABLE HANDLER]: Trying to store field {0} for {1} which is unexpectedly null", + "[MYSQL GENERIC TABLE HANDLER]: Trying to store field {0} for {1} which is unexpectedly null", fi.Name, row)); - + cmd.Parameters.AddWithValue(fi.Name, fi.GetValue(row).ToString()); } diff --git a/OpenSim/Data/MySQL/MySQLGroupsData.cs b/OpenSim/Data/MySQL/MySQLGroupsData.cs index 5734d19038..4e73ee7186 100644 --- a/OpenSim/Data/MySQL/MySQLGroupsData.cs +++ b/OpenSim/Data/MySQL/MySQLGroupsData.cs @@ -133,10 +133,10 @@ namespace OpenSim.Data.MySQL public bool DeleteMember(UUID groupID, string pricipalID) { - return m_Membership.Delete(new string[] { "GroupID", "PrincipalID" }, + return m_Membership.Delete(new string[] { "GroupID", "PrincipalID" }, new string[] { groupID.ToString(), pricipalID }); } - + public int MemberCount(UUID groupID) { return (int)m_Membership.GetCount("GroupID", groupID.ToString()); @@ -168,7 +168,7 @@ namespace OpenSim.Data.MySQL public bool DeleteRole(UUID groupID, UUID roleID) { - return m_Roles.Delete(new string[] { "GroupID", "RoleID" }, + return m_Roles.Delete(new string[] { "GroupID", "RoleID" }, new string[] { groupID.ToString(), roleID.ToString() }); } @@ -360,7 +360,7 @@ namespace OpenSim.Data.MySQL get { return GetType().Assembly; } } - public MySqlGroupsGroupsHandler(string connectionString, string realm, string store) + public MySqlGroupsGroupsHandler(string connectionString, string realm, string store) : base(connectionString, realm, store) { } @@ -375,7 +375,7 @@ namespace OpenSim.Data.MySQL get { return GetType().Assembly; } } - public MySqlGroupsMembershipHandler(string connectionString, string realm) + public MySqlGroupsMembershipHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } @@ -390,7 +390,7 @@ namespace OpenSim.Data.MySQL get { return GetType().Assembly; } } - public MySqlGroupsRolesHandler(string connectionString, string realm) + public MySqlGroupsRolesHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } @@ -405,7 +405,7 @@ namespace OpenSim.Data.MySQL get { return GetType().Assembly; } } - public MySqlGroupsRoleMembershipHandler(string connectionString, string realm) + public MySqlGroupsRoleMembershipHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } @@ -420,7 +420,7 @@ namespace OpenSim.Data.MySQL get { return GetType().Assembly; } } - public MySqlGroupsInvitesHandler(string connectionString, string realm) + public MySqlGroupsInvitesHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } @@ -447,7 +447,7 @@ namespace OpenSim.Data.MySQL get { return GetType().Assembly; } } - public MySqlGroupsNoticesHandler(string connectionString, string realm) + public MySqlGroupsNoticesHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } @@ -475,7 +475,7 @@ namespace OpenSim.Data.MySQL get { return GetType().Assembly; } } - public MySqlGroupsPrincipalsHandler(string connectionString, string realm) + public MySqlGroupsPrincipalsHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } diff --git a/OpenSim/Data/MySQL/MySQLInventoryData.cs b/OpenSim/Data/MySQL/MySQLInventoryData.cs index e9b10f3cdf..382d4a5c33 100644 --- a/OpenSim/Data/MySQL/MySQLInventoryData.cs +++ b/OpenSim/Data/MySQL/MySQLInventoryData.cs @@ -288,7 +288,7 @@ namespace OpenSim.Data.MySQL // TODO: this is to handle a case where NULLs creep in there, which we are not sure is endemic to the system, or legacy. It would be nice to live fix these. // (DBGuid.FromDB() reads db NULLs as well, returns UUID.Zero) item.CreatorId = reader["creatorID"].ToString(); - + // Be a bit safer in parsing these because the // database doesn't enforce them to be not null, and // the inventory still works if these are weird in the @@ -453,7 +453,7 @@ namespace OpenSim.Data.MySQL itemName = item.Name.Substring(0, 64); m_log.Warn("[INVENTORY DB]: Name field truncated from " + item.Name.Length + " to " + itemName.Length + " characters on add item"); } - + string itemDesc = item.Description; if (item.Description.Length > 128) { @@ -490,10 +490,10 @@ namespace OpenSim.Data.MySQL result.Parameters.AddWithValue("?groupID", item.GroupID); result.Parameters.AddWithValue("?groupOwned", item.GroupOwned); result.Parameters.AddWithValue("?flags", item.Flags); - + lock (m_dbLock) result.ExecuteNonQuery(); - + result.Dispose(); } @@ -630,7 +630,7 @@ namespace OpenSim.Data.MySQL { cmd.Parameters.AddWithValue("?folderID", folder.ID.ToString()); cmd.Parameters.AddWithValue("?parentFolderID", folder.ParentID.ToString()); - + try { lock (m_dbLock) @@ -860,7 +860,7 @@ namespace OpenSim.Data.MySQL deleteOneFolder(folderID); deleteItemsInFolder(folderID); } - + public List fetchActiveGestures(UUID avatarID) { lock (m_dbLock) diff --git a/OpenSim/Data/MySQL/MySQLMigrations.cs b/OpenSim/Data/MySQL/MySQLMigrations.cs index 81a0e837ea..2043dae052 100644 --- a/OpenSim/Data/MySQL/MySQLMigrations.cs +++ b/OpenSim/Data/MySQL/MySQLMigrations.cs @@ -39,16 +39,16 @@ namespace OpenSim.Data.MySQL { /// This is a MySQL-customized migration processor. The only difference is in how /// it executes SQL scripts (using MySqlScript instead of MyCommand) - /// + /// /// public class MySqlMigration : Migration { public MySqlMigration() : base() - { + { } - public MySqlMigration(DbConnection conn, Assembly assem, string subtype, string type) : + public MySqlMigration(DbConnection conn, Assembly assem, string subtype, string type) : base(conn, assem, subtype, type) { } diff --git a/OpenSim/Data/MySQL/MySQLOfflineIMData.cs b/OpenSim/Data/MySQL/MySQLOfflineIMData.cs index bafd204a32..7608858d2c 100644 --- a/OpenSim/Data/MySQL/MySQLOfflineIMData.cs +++ b/OpenSim/Data/MySQL/MySQLOfflineIMData.cs @@ -50,7 +50,7 @@ namespace OpenSim.Data.MySQL using (MySqlCommand cmd = new MySqlCommand()) { cmd.CommandText = String.Format("delete from {0} where TMStamp < NOW() - INTERVAL 2 WEEK", m_Realm); - + ExecuteNonQuery(cmd); } diff --git a/OpenSim/Data/MySQL/MySQLPresenceData.cs b/OpenSim/Data/MySQL/MySQLPresenceData.cs index 3f906399ec..70aca5f271 100644 --- a/OpenSim/Data/MySQL/MySQLPresenceData.cs +++ b/OpenSim/Data/MySQL/MySQLPresenceData.cs @@ -66,9 +66,9 @@ namespace OpenSim.Data.MySQL using (MySqlCommand cmd = new MySqlCommand()) { cmd.CommandText = String.Format("delete from {0} where `RegionID`=?RegionID", m_Realm); - + cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); - + ExecuteNonQuery(cmd); } } @@ -85,10 +85,10 @@ namespace OpenSim.Data.MySQL using (MySqlCommand cmd = new MySqlCommand()) { cmd.CommandText = String.Format("update {0} set RegionID=?RegionID, LastSeen=NOW() where `SessionID`=?SessionID", m_Realm); - + cmd.Parameters.AddWithValue("?SessionID", sessionID.ToString()); cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); - + if (ExecuteNonQuery(cmd) == 0) return false; } diff --git a/OpenSim/Data/MySQL/MySQLRegionData.cs b/OpenSim/Data/MySQL/MySQLRegionData.cs index 99d4944b52..0e55285451 100644 --- a/OpenSim/Data/MySQL/MySQLRegionData.cs +++ b/OpenSim/Data/MySQL/MySQLRegionData.cs @@ -410,7 +410,7 @@ namespace OpenSim.Data.MySQL using (MySqlCommand cmd = new MySqlCommand(command)) { cmd.Parameters.AddWithValue("?scopeID", scopeID.ToString()); - + return RunCommand(cmd); } } diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index 2aaa2ff553..8278c0ec20 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -55,7 +55,7 @@ namespace OpenSim.Data.MySQL /// /// This lock was being used to serialize database operations when the connection was shared, but this has /// been unnecessary for a long time after we switched to using MySQL's underlying connection pooling instead. - /// FIXME: However, the locks remain in many places since they are effectively providing a level of + /// FIXME: However, the locks remain in many places since they are effectively providing a level of /// transactionality. This should be replaced by more efficient database transactions which would not require /// unrelated operations to block each other or unrelated operations on the same tables from blocking each /// other. @@ -268,7 +268,7 @@ namespace OpenSim.Data.MySQL public virtual void RemoveObject(UUID obj, UUID regionUUID) { // m_log.DebugFormat("[REGION DB]: Deleting scene object {0} from {1} in database", obj, regionUUID); - + List uuids = new List(); // Formerly, this used to check the region UUID. @@ -509,7 +509,7 @@ namespace OpenSim.Data.MySQL #region Prim Inventory Loading // Instead of attempting to LoadItems on every prim, - // most of which probably have no items... get a + // most of which probably have no items... get a // list from DB of all prims which have items and // LoadItems only on those List primsWithInventory = new List(); @@ -807,7 +807,7 @@ namespace OpenSim.Data.MySQL "UserLocationX, UserLocationY, UserLocationZ, " + "UserLookAtX, UserLookAtY, UserLookAtZ, " + "AuthbuyerID, OtherCleanTime, Dwell, MediaType, MediaDescription, " + - "MediaSize, MediaLoop, ObscureMusic, ObscureMedia, " + + "MediaSize, MediaLoop, ObscureMusic, ObscureMedia, " + "SeeAVs, AnyAVSounds, GroupAVSounds) values (" + "?UUID, ?RegionUUID, " + "?LocalLandID, ?Bitmap, ?Name, ?Description, " + @@ -1081,7 +1081,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("cloud_scroll_y", wl.cloudScrollY); cmd.Parameters.AddWithValue("cloud_scroll_y_lock", wl.cloudScrollYLock); cmd.Parameters.AddWithValue("draw_classic_clouds", wl.drawClassicClouds); - + ExecuteNonQuery(cmd); } } @@ -1273,7 +1273,7 @@ namespace OpenSim.Data.MySQL { SceneObjectPart prim = new SceneObjectPart(); - // depending on the MySQL connector version, CHAR(36) may be already converted to Guid! + // depending on the MySQL connector version, CHAR(36) may be already converted to Guid! prim.UUID = DBGuid.FromDB(row["UUID"]); prim.CreatorIdentification = (string)row["CreatorID"]; prim.OwnerID = DBGuid.FromDB(row["OwnerID"]); @@ -1401,11 +1401,11 @@ namespace OpenSim.Data.MySQL prim.CollisionSound = DBGuid.FromDB(row["CollisionSound"]); prim.CollisionSoundVolume = (float)(double)row["CollisionSoundVolume"]; - + prim.PassTouches = ((sbyte)row["PassTouches"] != 0); prim.PassCollisions = ((sbyte)row["PassCollisions"] != 0); prim.LinkNum = (int)row["LinkNumber"]; - + if (!(row["MediaURL"] is System.DBNull)) prim.MediaUrl = (string)row["MediaURL"]; @@ -1421,7 +1421,7 @@ namespace OpenSim.Data.MySQL if (!(row["DynAttrs"] is System.DBNull)) prim.DynAttrs = DAMap.FromXml((string)row["DynAttrs"]); else - prim.DynAttrs = new DAMap(); + prim.DynAttrs = new DAMap(); if (!(row["KeyframeMotion"] is DBNull)) { @@ -1543,10 +1543,10 @@ namespace OpenSim.Data.MySQL newSettings.Covenant = DBGuid.FromDB(row["covenant"]); newSettings.CovenantChangedDateTime = Convert.ToInt32(row["covenant_datetime"]); newSettings.LoadedCreationDateTime = Convert.ToInt32(row["loaded_creation_datetime"]); - + if (row["loaded_creation_id"] is DBNull) newSettings.LoadedCreationID = ""; - else + else newSettings.LoadedCreationID = (String) row["loaded_creation_id"]; newSettings.TerrainImageID = DBGuid.FromDB(row["map_tile_ID"]); @@ -2023,7 +2023,7 @@ namespace OpenSim.Data.MySQL s.State = (byte)(int)row["State"]; s.LastAttachPoint = (byte)(int)row["LastAttachPoint"]; - + if (!(row["Media"] is System.DBNull)) s.Media = PrimitiveBaseShape.MediaList.FromXml((string)row["Media"]); @@ -2103,13 +2103,13 @@ namespace OpenSim.Data.MySQL "?flags, ?itemID, ?primID, ?assetID, " + "?parentFolderID, ?creatorID, ?ownerID, " + "?groupID, ?lastOwnerID)"; - + foreach (TaskInventoryItem item in items) { cmd.Parameters.Clear(); - + FillItemCommand(cmd, item); - + ExecuteNonQuery(cmd); } } diff --git a/OpenSim/Data/MySQL/MySQLUserProfilesData.cs b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs index c389ae4c17..8af2a3ef29 100644 --- a/OpenSim/Data/MySQL/MySQLUserProfilesData.cs +++ b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs @@ -40,39 +40,39 @@ namespace OpenSim.Data.MySQL public class UserProfilesData: IProfilesData { static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + #region Properites string ConnectionString { get; set; } - + protected virtual Assembly Assembly { get { return GetType().Assembly; } } - + #endregion Properties - + #region class Member Functions public UserProfilesData(string connectionString) { ConnectionString = connectionString; Init(); } - + void Init() { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) { dbcon.Open(); - + Migration m = new Migration(dbcon, Assembly, "UserProfiles"); m.Update(); } } #endregion Member Functions - + #region Classifieds Queries /// /// Gets the classified records. @@ -86,7 +86,7 @@ namespace OpenSim.Data.MySQL public OSDArray GetClassifiedRecords(UUID creatorId) { OSDArray data = new OSDArray(); - + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) { string query = "SELECT classifieduuid, name FROM classifieds WHERE creatoruuid = ?Id"; @@ -102,7 +102,7 @@ namespace OpenSim.Data.MySQL { OSDMap n = new OSDMap(); UUID Id = UUID.Zero; - + string Name = null; try { @@ -124,12 +124,12 @@ namespace OpenSim.Data.MySQL } return data; } - + public bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result) { string query = string.Empty; - - + + query += "INSERT INTO classifieds ("; query += "`classifieduuid`,"; query += "`creatoruuid`,"; @@ -173,21 +173,21 @@ namespace OpenSim.Data.MySQL query += "classifiedflags=?Flags, "; query += "priceforlisting=?ListingPrice, "; query += "snapshotuuid=?SnapshotId"; - + if(string.IsNullOrEmpty(ad.ParcelName)) ad.ParcelName = "Unknown"; if(ad.ParcelId == null) ad.ParcelId = UUID.Zero; if(string.IsNullOrEmpty(ad.Description)) ad.Description = "No Description"; - + DateTime epoch = new DateTime(1970, 1, 1); DateTime now = DateTime.Now; TimeSpan epochnow = now - epoch; TimeSpan duration; DateTime expiration; TimeSpan epochexp; - + if(ad.Flags == 2) { duration = new TimeSpan(7,0,0,0); @@ -202,7 +202,7 @@ namespace OpenSim.Data.MySQL } ad.CreationDate = (int)epochnow.TotalSeconds; ad.ExpirationDate = (int)epochexp.TotalSeconds; - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) @@ -225,7 +225,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("?ParcelName", ad.ParcelName.ToString()); cmd.Parameters.AddWithValue("?Flags", ad.Flags.ToString()); cmd.Parameters.AddWithValue("?ListingPrice", ad.Price.ToString ()); - + cmd.ExecuteNonQuery(); } } @@ -239,20 +239,20 @@ namespace OpenSim.Data.MySQL } return true; } - + public bool DeleteClassifiedRecord(UUID recordId) { string query = string.Empty; - + query += "DELETE FROM classifieds WHERE "; query += "classifieduuid = ?recordId"; - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) { dbcon.Open(); - + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) { cmd.Parameters.AddWithValue("?recordId", recordId.ToString()); @@ -268,14 +268,14 @@ namespace OpenSim.Data.MySQL } return true; } - + public bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result) { string query = string.Empty; - + query += "SELECT * FROM classifieds WHERE "; query += "classifieduuid = ?AdId"; - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) @@ -284,7 +284,7 @@ namespace OpenSim.Data.MySQL using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) { cmd.Parameters.AddWithValue("?AdId", ad.ClassifiedId.ToString()); - + using (MySqlDataReader reader = cmd.ExecuteReader()) { if(reader.Read ()) @@ -303,7 +303,7 @@ namespace OpenSim.Data.MySQL ad.SimName = reader.GetString("simname"); ad.GlobalPos = reader.GetString("posglobal"); ad.ParcelName = reader.GetString("parcelname"); - + } } } @@ -318,16 +318,16 @@ namespace OpenSim.Data.MySQL return true; } #endregion Classifieds Queries - + #region Picks Queries public OSDArray GetAvatarPicks(UUID avatarId) { string query = string.Empty; - + query += "SELECT `pickuuid`,`name` FROM userpicks WHERE "; query += "creatoruuid = ?Id"; OSDArray data = new OSDArray(); - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) @@ -336,7 +336,7 @@ namespace OpenSim.Data.MySQL using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) { cmd.Parameters.AddWithValue("?Id", avatarId.ToString()); - + using (MySqlDataReader reader = cmd.ExecuteReader()) { if(reader.HasRows) @@ -344,7 +344,7 @@ namespace OpenSim.Data.MySQL while (reader.Read()) { OSDMap record = new OSDMap(); - + record.Add("pickuuid",OSD.FromString((string)reader["pickuuid"])); record.Add("name",OSD.FromString((string)reader["name"])); data.Add(record); @@ -361,16 +361,16 @@ namespace OpenSim.Data.MySQL } return data; } - + public UserProfilePick GetPickInfo(UUID avatarId, UUID pickId) { string query = string.Empty; UserProfilePick pick = new UserProfilePick(); - + query += "SELECT * FROM userpicks WHERE "; query += "creatoruuid = ?CreatorId AND "; query += "pickuuid = ?PickId"; - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) @@ -380,18 +380,18 @@ namespace OpenSim.Data.MySQL { cmd.Parameters.AddWithValue("?CreatorId", avatarId.ToString()); cmd.Parameters.AddWithValue("?PickId", pickId.ToString()); - + using (MySqlDataReader reader = cmd.ExecuteReader()) { if(reader.HasRows) { reader.Read(); - + string description = (string)reader["description"]; - + if (string.IsNullOrEmpty(description)) description = "No description given."; - + UUID.TryParse((string)reader["pickuuid"], out pick.PickId); UUID.TryParse((string)reader["creatoruuid"], out pick.CreatorId); UUID.TryParse((string)reader["parceluuid"], out pick.ParcelId); @@ -419,11 +419,11 @@ namespace OpenSim.Data.MySQL } return pick; } - + public bool UpdatePicksRecord(UserProfilePick pick) - { + { string query = string.Empty; - + query += "INSERT INTO userpicks VALUES ("; query += "?PickId,"; query += "?CreatorId,"; @@ -449,7 +449,7 @@ namespace OpenSim.Data.MySQL query += "pickuuid=?PickId,"; query += "posglobal=?GlobalPos,"; query += "gatekeeper=?Gatekeeper"; - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) @@ -471,7 +471,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("?Gatekeeper",pick.Gatekeeper); cmd.Parameters.AddWithValue("?SortOrder", pick.SortOrder.ToString ()); cmd.Parameters.AddWithValue("?Enabled", pick.Enabled.ToString()); - + cmd.ExecuteNonQuery(); } } @@ -484,24 +484,24 @@ namespace OpenSim.Data.MySQL } return true; } - + public bool DeletePicksRecord(UUID pickId) { string query = string.Empty; - + query += "DELETE FROM userpicks WHERE "; query += "pickuuid = ?PickId"; - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) { dbcon.Open(); - + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) { cmd.Parameters.AddWithValue("?PickId", pickId.ToString()); - + cmd.ExecuteNonQuery(); } } @@ -515,12 +515,12 @@ namespace OpenSim.Data.MySQL return true; } #endregion Picks Queries - + #region Avatar Notes Queries public bool GetAvatarNotes(ref UserProfileNotes notes) { // WIP string query = string.Empty; - + query += "SELECT `notes` FROM usernotes WHERE "; query += "useruuid = ?Id AND "; query += "targetuuid = ?TargetId"; @@ -534,7 +534,7 @@ namespace OpenSim.Data.MySQL { cmd.Parameters.AddWithValue("?Id", notes.UserId.ToString()); cmd.Parameters.AddWithValue("?TargetId", notes.TargetId.ToString()); - + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { if(reader.HasRows) @@ -557,12 +557,12 @@ namespace OpenSim.Data.MySQL } return true; } - + public bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result) - { + { string query = string.Empty; bool remove; - + if(string.IsNullOrEmpty(note.Notes)) { remove = true; @@ -581,7 +581,7 @@ namespace OpenSim.Data.MySQL query += "UPDATE "; query += "notes=?Notes"; } - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) @@ -593,7 +593,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("?Notes", note.Notes); cmd.Parameters.AddWithValue("?TargetId", note.TargetId.ToString ()); cmd.Parameters.AddWithValue("?UserId", note.UserId.ToString()); - + cmd.ExecuteNonQuery(); } } @@ -605,18 +605,18 @@ namespace OpenSim.Data.MySQL return false; } return true; - + } #endregion Avatar Notes Queries - + #region Avatar Properties public bool GetAvatarProperties(ref UserProfileProperties props, ref string result) { string query = string.Empty; - + query += "SELECT * FROM userprofile WHERE "; query += "useruuid = ?Id"; - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) @@ -625,7 +625,7 @@ namespace OpenSim.Data.MySQL using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) { cmd.Parameters.AddWithValue("?Id", props.UserId.ToString()); - + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { if(reader.HasRows) @@ -649,7 +649,7 @@ namespace OpenSim.Data.MySQL { m_log.DebugFormat("[PROFILES_DATA]" + ": No data for {0}", props.UserId); - + props.WebUrl = string.Empty; props.ImageId = UUID.Zero; props.AboutText = string.Empty; @@ -730,11 +730,11 @@ namespace OpenSim.Data.MySQL } return true; } - + public bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result) - { + { string query = string.Empty; - + query += "UPDATE userprofile SET "; query += "profileURL=?profileURL, "; query += "profileImage=?image, "; @@ -742,7 +742,7 @@ namespace OpenSim.Data.MySQL query += "profileFirstImage=?firstlifeimage,"; query += "profileFirstText=?firstlifetext "; query += "WHERE useruuid=?uuid"; - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) @@ -756,7 +756,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("?firstlifeimage", props.FirstLifeImageId.ToString()); cmd.Parameters.AddWithValue("?firstlifetext", props.FirstLifeText); cmd.Parameters.AddWithValue("?uuid", props.UserId.ToString()); - + cmd.ExecuteNonQuery(); } } @@ -765,18 +765,18 @@ namespace OpenSim.Data.MySQL { m_log.ErrorFormat("[PROFILES_DATA]" + ": AgentPropertiesUpdate exception {0}", e.Message); - + return false; } return true; } #endregion Avatar Properties - + #region Avatar Interests public bool UpdateAvatarInterests(UserProfileProperties up, ref string result) - { + { string query = string.Empty; - + query += "UPDATE userprofile SET "; query += "profileWantToMask=?WantMask, "; query += "profileWantToText=?WantText,"; @@ -784,7 +784,7 @@ namespace OpenSim.Data.MySQL query += "profileSkillsText=?SkillsText, "; query += "profileLanguages=?Languages "; query += "WHERE useruuid=?uuid"; - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) @@ -798,7 +798,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("?SkillsText", up.SkillsText); cmd.Parameters.AddWithValue("?Languages", up.Language); cmd.Parameters.AddWithValue("?uuid", up.UserId.ToString()); - + cmd.ExecuteNonQuery(); } } @@ -820,8 +820,8 @@ namespace OpenSim.Data.MySQL string query = "SELECT `snapshotuuid` FROM {0} WHERE `creatoruuid` = ?Id"; // Get classified image assets - - + + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) @@ -831,7 +831,7 @@ namespace OpenSim.Data.MySQL using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`classifieds`"), dbcon)) { cmd.Parameters.AddWithValue("?Id", avatarId.ToString()); - + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { if(reader.HasRows) @@ -850,7 +850,7 @@ namespace OpenSim.Data.MySQL using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`userpicks`"), dbcon)) { cmd.Parameters.AddWithValue("?Id", avatarId.ToString()); - + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { if(reader.HasRows) @@ -862,7 +862,7 @@ namespace OpenSim.Data.MySQL } } } - + dbcon.Close(); dbcon.Open(); @@ -871,7 +871,7 @@ namespace OpenSim.Data.MySQL using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`userpicks`"), dbcon)) { cmd.Parameters.AddWithValue("?Id", avatarId.ToString()); - + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { if(reader.HasRows) @@ -893,7 +893,7 @@ namespace OpenSim.Data.MySQL } return data; } - + #region User Preferences public bool GetUserPreferences(ref UserPreferences pref, ref string result) { @@ -987,16 +987,16 @@ namespace OpenSim.Data.MySQL return true; } #endregion User Preferences - + #region Integration public bool GetUserAppData(ref UserAppData props, ref string result) { string query = string.Empty; - + query += "SELECT * FROM `userdata` WHERE "; query += "UserId = ?Id AND "; query += "TagId = ?TagId"; - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) @@ -1006,7 +1006,7 @@ namespace OpenSim.Data.MySQL { cmd.Parameters.AddWithValue("?Id", props.UserId.ToString()); cmd.Parameters.AddWithValue ("?TagId", props.TagId.ToString()); - + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { if(reader.HasRows) @@ -1022,7 +1022,7 @@ namespace OpenSim.Data.MySQL query += "?TagId,"; query += "?DataKey,"; query += "?DataVal) "; - + using (MySqlCommand put = new MySqlCommand(query, dbcon)) { put.Parameters.AddWithValue("?UserId", props.UserId.ToString()); @@ -1048,16 +1048,16 @@ namespace OpenSim.Data.MySQL } public bool SetUserAppData(UserAppData props, ref string result) - { + { string query = string.Empty; - + query += "UPDATE userdata SET "; query += "TagId = ?TagId, "; query += "DataKey = ?DataKey, "; query += "DataVal = ?DataVal WHERE "; query += "UserId = ?UserId AND "; query += "TagId = ?TagId"; - + try { using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) diff --git a/OpenSim/Data/MySQL/MySQLXAssetData.cs b/OpenSim/Data/MySQL/MySQLXAssetData.cs index ec2bcc69e9..2c6acdef32 100644 --- a/OpenSim/Data/MySQL/MySQLXAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLXAssetData.cs @@ -209,7 +209,7 @@ namespace OpenSim.Data.MySQL { assetName = asset.Name.Substring(0, AssetBase.MAX_ASSET_NAME); m_log.WarnFormat( - "[XASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", + "[XASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", asset.Name, asset.ID, asset.Name.Length, assetName.Length); } @@ -218,7 +218,7 @@ namespace OpenSim.Data.MySQL { assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); m_log.WarnFormat( - "[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + "[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); } @@ -341,7 +341,7 @@ namespace OpenSim.Data.MySQL catch (Exception) { m_log.ErrorFormat( - "[XASSET MYSQL DB]: Failure updating access_time for asset {0} with name {1}", + "[XASSET MYSQL DB]: Failure updating access_time for asset {0} with name {1}", assetMetadata.ID, assetMetadata.Name); } } diff --git a/OpenSim/Data/MySQL/MySQLXInventoryData.cs b/OpenSim/Data/MySQL/MySQLXInventoryData.cs index 9a0044eb8b..4e41fec9cd 100644 --- a/OpenSim/Data/MySQL/MySQLXInventoryData.cs +++ b/OpenSim/Data/MySQL/MySQLXInventoryData.cs @@ -80,7 +80,7 @@ namespace OpenSim.Data.MySQL return m_Items.Store(item); } - + public bool DeleteFolders(string field, string val) { return m_Folders.Delete(field, val); @@ -220,12 +220,12 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString()); cmd.Parameters.AddWithValue("?AssetID", assetID.ToString()); - + using (IDataReader reader = cmd.ExecuteReader()) { int perms = 0; - + if (reader.Read()) { perms = Convert.ToInt32(reader["inventoryCurrentPermissions"]); diff --git a/OpenSim/Data/Null/NullEstateData.cs b/OpenSim/Data/Null/NullEstateData.cs index 57592f180d..9f2289600c 100755 --- a/OpenSim/Data/Null/NullEstateData.cs +++ b/OpenSim/Data/Null/NullEstateData.cs @@ -102,19 +102,19 @@ namespace OpenSim.Data.Null { return new EstateSettings(); } - + public List LoadEstateSettingsAll() { List allEstateSettings = new List(); allEstateSettings.Add(GetEstate()); return allEstateSettings; } - + public List GetEstatesAll() { List result = new List(); result.Add((int)GetEstate().EstateID); - return result; + return result; } public List GetEstates(string search) diff --git a/OpenSim/Data/Null/NullFriendsData.cs b/OpenSim/Data/Null/NullFriendsData.cs index 473999fdb2..dc9cd38758 100644 --- a/OpenSim/Data/Null/NullFriendsData.cs +++ b/OpenSim/Data/Null/NullFriendsData.cs @@ -79,7 +79,7 @@ namespace OpenSim.Data.Null { return fdata.PrincipalID == userID.ToString(); }); - + if (lst != null) { lst.ForEach(f => @@ -87,14 +87,14 @@ namespace OpenSim.Data.Null FriendsData f2 = m_Data.Find(candidateF2 => f.Friend == candidateF2.PrincipalID); if (f2 != null) f.Data["TheirFlags"] = f2.Data["Flags"]; - + // m_log.DebugFormat( // "[NULL FRIENDS DATA]: Got {0} {1} {2} for {3}", // f.Friend, f.Data["Flags"], f2 != null ? f.Data["TheirFlags"] : "not found!", f.PrincipalID); }); - + // m_log.DebugFormat("[NULL FRIENDS DATA]: Got {0} friends for {1}", lst.Count, userID); - + return lst.ToArray(); } } @@ -134,7 +134,7 @@ namespace OpenSim.Data.Null // m_log.DebugFormat( // "[NULL FRIENDS DATA]: Deleting friend {0} {1} for {2}", // friend.Friend, friend.Data["Flags"], friend.PrincipalID); - + m_Data.Remove(friend); return true; } diff --git a/OpenSim/Data/Null/NullPresenceData.cs b/OpenSim/Data/Null/NullPresenceData.cs index aff0b0b479..8c442c9c5b 100644 --- a/OpenSim/Data/Null/NullPresenceData.cs +++ b/OpenSim/Data/Null/NullPresenceData.cs @@ -39,7 +39,7 @@ namespace OpenSim.Data.Null public class NullPresenceData : IPresenceData { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + public static NullPresenceData Instance; Dictionary m_presenceData = new Dictionary(); @@ -100,7 +100,7 @@ namespace OpenSim.Data.Null { if (Instance != this) return Instance.ReportAgent(sessionID, regionID); - + if (m_presenceData.ContainsKey(sessionID)) { m_presenceData[sessionID].RegionID = regionID; @@ -129,7 +129,7 @@ namespace OpenSim.Data.Null // Console.WriteLine("HOME for " + p.UserID + " is " + (p.Data.ContainsKey("HomeRegionID") ? p.Data["HomeRegionID"] : "Not found")); } } - + return presences.ToArray(); } else if (field == "SessionID") @@ -172,7 +172,7 @@ namespace OpenSim.Data.Null { // m_log.DebugFormat( // "[NULL PRESENCE DATA]: Deleting presence data for field {0} with parameter {1}", field, data); - + if (Instance != this) return Instance.Delete(field, data); diff --git a/OpenSim/Data/Null/NullUserAccountData.cs b/OpenSim/Data/Null/NullUserAccountData.cs index 241616ba3c..6d2e05ac23 100644 --- a/OpenSim/Data/Null/NullUserAccountData.cs +++ b/OpenSim/Data/Null/NullUserAccountData.cs @@ -40,7 +40,7 @@ namespace OpenSim.Data.Null public class NullUserAccountData : IUserAccountData { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private Dictionary m_DataByUUID = new Dictionary(); private Dictionary m_DataByName = new Dictionary(); private Dictionary m_DataByEmail = new Dictionary(); @@ -48,7 +48,7 @@ namespace OpenSim.Data.Null public NullUserAccountData(string connectionString, string realm) { // m_log.DebugFormat( -// "[NULL USER ACCOUNT DATA]: Initializing new NullUserAccountData with connectionString [{0}], realm [{1}]", +// "[NULL USER ACCOUNT DATA]: Initializing new NullUserAccountData with connectionString [{0}], realm [{1}]", // connectionString, realm); } @@ -65,12 +65,12 @@ namespace OpenSim.Data.Null // if (m_log.IsDebugEnabled) // { // m_log.DebugFormat( -// "[NULL USER ACCOUNT DATA]: Called Get with fields [{0}], values [{1}]", +// "[NULL USER ACCOUNT DATA]: Called Get with fields [{0}], values [{1}]", // string.Join(", ", fields), string.Join(", ", values)); // } - + UserAccountData[] userAccounts = new UserAccountData[0]; - + List fieldsLst = new List(fields); if (fieldsLst.Contains("PrincipalID")) { @@ -79,33 +79,33 @@ namespace OpenSim.Data.Null if (UUID.TryParse(values[i], out id)) if (m_DataByUUID.ContainsKey(id)) userAccounts = new UserAccountData[] { m_DataByUUID[id] }; - } + } else if (fieldsLst.Contains("FirstName") && fieldsLst.Contains("LastName")) { int findex = fieldsLst.IndexOf("FirstName"); int lindex = fieldsLst.IndexOf("LastName"); if (m_DataByName.ContainsKey(values[findex] + " " + values[lindex])) - { + { userAccounts = new UserAccountData[] { m_DataByName[values[findex] + " " + values[lindex]] }; } - } + } else if (fieldsLst.Contains("Email")) { int i = fieldsLst.IndexOf("Email"); if (m_DataByEmail.ContainsKey(values[i])) userAccounts = new UserAccountData[] { m_DataByEmail[values[i]] }; } - + // if (m_log.IsDebugEnabled) // { // StringBuilder sb = new StringBuilder(); // foreach (UserAccountData uad in userAccounts) // sb.AppendFormat("({0} {1} {2}) ", uad.FirstName, uad.LastName, uad.PrincipalID); -// +// // m_log.DebugFormat( // "[NULL USER ACCOUNT DATA]: Returning {0} user accounts out of {1}: [{2}]", userAccounts.Length, m_DataByName.Count, sb); // } - + return userAccounts; } @@ -113,16 +113,16 @@ namespace OpenSim.Data.Null { if (data == null) return false; - + m_log.DebugFormat( - "[NULL USER ACCOUNT DATA]: Storing user account {0} {1} {2} {3}", + "[NULL USER ACCOUNT DATA]: Storing user account {0} {1} {2} {3}", data.FirstName, data.LastName, data.PrincipalID, this.GetHashCode()); - + m_DataByUUID[data.PrincipalID] = data; m_DataByName[data.FirstName + " " + data.LastName] = data; if (data.Data.ContainsKey("Email") && data.Data["Email"] != null && data.Data["Email"] != string.Empty) m_DataByEmail[data.Data["Email"]] = data; - + // m_log.DebugFormat("m_DataByUUID count is {0}, m_DataByName count is {1}", m_DataByUUID.Count, m_DataByName.Count); return true; @@ -132,7 +132,7 @@ namespace OpenSim.Data.Null { // m_log.DebugFormat( // "[NULL USER ACCOUNT DATA]: Called GetUsers with scope [{0}], query [{1}]", scopeID, query); - + string[] words = query.Split(new char[] { ' ' }); for (int i = 0; i < words.Length; i++) diff --git a/OpenSim/Data/PGSQL/PGSQLAssetData.cs b/OpenSim/Data/PGSQL/PGSQLAssetData.cs index 81adb034a9..7b79521591 100644 --- a/OpenSim/Data/PGSQL/PGSQLAssetData.cs +++ b/OpenSim/Data/PGSQL/PGSQLAssetData.cs @@ -151,35 +151,35 @@ namespace OpenSim.Data.PGSQL /// the asset override public bool StoreAsset(AssetBase asset) { - + string sql = @"UPDATE assets set name = :name, description = :description, " + "\"assetType\" " + @" = :assetType, local = :local, temporary = :temporary, creatorid = :creatorid, data = :data WHERE id=:id; INSERT INTO assets - (id, name, description, " + "\"assetType\" " + @", local, + (id, name, description, " + "\"assetType\" " + @", local, temporary, create_time, access_time, creatorid, asset_flags, data) - Select :id, :name, :description, :assetType, :local, + Select :id, :name, :description, :assetType, :local, :temporary, :create_time, :access_time, :creatorid, :asset_flags, :data - Where not EXISTS(SELECT * FROM assets WHERE id=:id) + Where not EXISTS(SELECT * FROM assets WHERE id=:id) "; - + string assetName = asset.Name; if (asset.Name.Length > AssetBase.MAX_ASSET_NAME) { assetName = asset.Name.Substring(0, AssetBase.MAX_ASSET_NAME); m_log.WarnFormat( - "[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", + "[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", asset.Name, asset.ID, asset.Name.Length, assetName.Length); } - + string assetDescription = asset.Description; if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) { assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); m_log.WarnFormat( - "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); } @@ -278,7 +278,7 @@ namespace OpenSim.Data.PGSQL { List retList = new List(count); string sql = @" SELECT id, name, description, " + "\"assetType\"" + @", temporary, creatorid - FROM assets + FROM assets order by id limit :stop offset :start;"; diff --git a/OpenSim/Data/PGSQL/PGSQLAuthenticationData.cs b/OpenSim/Data/PGSQL/PGSQLAuthenticationData.cs index d174112f0f..8f83309f06 100644 --- a/OpenSim/Data/PGSQL/PGSQLAuthenticationData.cs +++ b/OpenSim/Data/PGSQL/PGSQLAuthenticationData.cs @@ -145,7 +145,7 @@ namespace OpenSim.Data.PGSQL updateBuilder.AppendFormat("\"{0}\" = :{0}",field); first = false; - + cmd.Parameters.Add(m_database.CreateParameter("" + field, data.Data[field])); } @@ -154,7 +154,7 @@ namespace OpenSim.Data.PGSQL cmd.CommandText = updateBuilder.ToString(); cmd.Connection = conn; cmd.Parameters.Add(m_database.CreateParameter("principalID", data.PrincipalID)); - + conn.Open(); if (cmd.ExecuteNonQuery() < 1) { @@ -195,7 +195,7 @@ namespace OpenSim.Data.PGSQL { if (System.Environment.TickCount - m_LastExpire > 30000) DoExpire(); - + string sql = "insert into tokens (uuid, token, validity) values (:principalID, :token, :lifetime)"; using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) diff --git a/OpenSim/Data/PGSQL/PGSQLAvatarData.cs b/OpenSim/Data/PGSQL/PGSQLAvatarData.cs index d9c49052d4..3d56d4d051 100644 --- a/OpenSim/Data/PGSQL/PGSQLAvatarData.cs +++ b/OpenSim/Data/PGSQL/PGSQLAvatarData.cs @@ -45,7 +45,7 @@ namespace OpenSim.Data.PGSQL IAvatarData { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + public PGSQLAvatarData(string connectionString, string realm) : base(connectionString, realm, "Avatar") { diff --git a/OpenSim/Data/PGSQL/PGSQLEstateData.cs b/OpenSim/Data/PGSQL/PGSQLEstateData.cs index b5ca235200..9489d6cec6 100644 --- a/OpenSim/Data/PGSQL/PGSQLEstateData.cs +++ b/OpenSim/Data/PGSQL/PGSQLEstateData.cs @@ -594,7 +594,7 @@ namespace OpenSim.Data.PGSQL public bool DeleteEstate(int estateID) { - // TODO: Implementation! + // TODO: Implementation! return false; } #endregion diff --git a/OpenSim/Data/PGSQL/PGSQLFriendsData.cs b/OpenSim/Data/PGSQL/PGSQLFriendsData.cs index a8413531fd..58dffedc2f 100644 --- a/OpenSim/Data/PGSQL/PGSQLFriendsData.cs +++ b/OpenSim/Data/PGSQL/PGSQLFriendsData.cs @@ -50,7 +50,7 @@ namespace OpenSim.Data.PGSQL } } - + public override bool Delete(string principalID, string friend) { UUID princUUID = UUID.Zero; @@ -97,7 +97,7 @@ namespace OpenSim.Data.PGSQL using (NpgsqlCommand cmd = new NpgsqlCommand()) { - cmd.CommandText = String.Format("select a.*,case when b.\"Flags\" is null then '-1' else b.\"Flags\" end as \"TheirFlags\" from {0} as a " + + cmd.CommandText = String.Format("select a.*,case when b.\"Flags\" is null then '-1' else b.\"Flags\" end as \"TheirFlags\" from {0} as a " + " left join {0} as b on a.\"PrincipalID\" = b.\"Friend\" and a.\"Friend\" = b.\"PrincipalID\" " + " where a.\"PrincipalID\" = :PrincipalID", m_Realm); cmd.Parameters.Add(m_database.CreateParameter("PrincipalID", principalID.ToString())); @@ -111,6 +111,6 @@ namespace OpenSim.Data.PGSQL { return GetFriends(principalID); } - + } } diff --git a/OpenSim/Data/PGSQL/PGSQLGenericTableHandler.cs b/OpenSim/Data/PGSQL/PGSQLGenericTableHandler.cs index 061de22eff..5b247200d3 100644 --- a/OpenSim/Data/PGSQL/PGSQLGenericTableHandler.cs +++ b/OpenSim/Data/PGSQL/PGSQLGenericTableHandler.cs @@ -64,7 +64,7 @@ namespace OpenSim.Data.PGSQL : base(connectionString) { m_Realm = realm; - + m_ConnectionString = connectionString; if (storeName != String.Empty) @@ -104,7 +104,7 @@ namespace OpenSim.Data.PGSQL m_FieldTypes = new Dictionary(); string query = string.Format(@"select column_name,data_type - from INFORMATION_SCHEMA.COLUMNS + from INFORMATION_SCHEMA.COLUMNS where table_name = lower('{0}'); ", m_Realm); @@ -232,7 +232,7 @@ namespace OpenSim.Data.PGSQL if (reader == null) return new T[0]; - CheckColumnNames(reader); + CheckColumnNames(reader); while (reader.Read()) { @@ -339,7 +339,7 @@ namespace OpenSim.Data.PGSQL names.Add(fi.Name); values.Add(":" + fi.Name); // Temporarily return more information about what field is unexpectedly null for - // http://opensimulator.org/mantis/view.php?id=5403. This might be due to a bug in the + // http://opensimulator.org/mantis/view.php?id=5403. This might be due to a bug in the // InventoryTransferModule or we may be required to substitute a DBNull here. if (fi.GetValue(row) == null) throw new NullReferenceException( @@ -395,11 +395,11 @@ namespace OpenSim.Data.PGSQL } string where = String.Join(" AND ", terms.ToArray()); query.AppendFormat(" WHERE {0} ", where); - + } cmd.Connection = conn; cmd.CommandText = query.ToString(); - + conn.Open(); if (cmd.ExecuteNonQuery() > 0) { @@ -416,7 +416,7 @@ namespace OpenSim.Data.PGSQL query.Append("\") values (" + String.Join(",", values.ToArray()) + ")"); cmd.Connection = conn; cmd.CommandText = query.ToString(); - + // m_log.WarnFormat("[PGSQLGenericTable]: Inserting into {0} sql {1}", m_Realm, cmd.CommandText); if (conn.State != ConnectionState.Open) diff --git a/OpenSim/Data/PGSQL/PGSQLGroupsData.cs b/OpenSim/Data/PGSQL/PGSQLGroupsData.cs index e257e7c723..6ef576bccc 100755 --- a/OpenSim/Data/PGSQL/PGSQLGroupsData.cs +++ b/OpenSim/Data/PGSQL/PGSQLGroupsData.cs @@ -37,7 +37,7 @@ using Npgsql; namespace OpenSim.Data.PGSQL { public class PGSQLGroupsData : IGroupsData - { + { private PGSqlGroupsGroupsHandler m_Groups; private PGSqlGroupsMembershipHandler m_Membership; private PGSqlGroupsRolesHandler m_Roles; @@ -83,17 +83,17 @@ namespace OpenSim.Data.PGSQL public GroupData[] RetrieveGroups(string pattern) { - + if (string.IsNullOrEmpty(pattern)) // True for where clause { pattern = " 1 ORDER BY lower(\"Name\") LIMIT 100"; - + return m_Groups.Get(pattern); } - else - { + else + { pattern = " \"ShowInList\" = 1 AND lower(\"Name\") LIKE lower('%" + pattern + "%') ORDER BY lower(\"Name\") LIMIT 100"; - + return m_Groups.Get(pattern, new NpgsqlParameter("pattern", pattern)); } } @@ -138,10 +138,10 @@ namespace OpenSim.Data.PGSQL public bool DeleteMember(UUID groupID, string pricipalID) { - return m_Membership.Delete(new string[] { "GroupID", "PrincipalID" }, + return m_Membership.Delete(new string[] { "GroupID", "PrincipalID" }, new string[] { groupID.ToString(), pricipalID }); } - + public int MemberCount(UUID groupID) { return (int)m_Membership.GetCount("GroupID", groupID.ToString()); @@ -173,7 +173,7 @@ namespace OpenSim.Data.PGSQL public bool DeleteRole(UUID groupID, UUID roleID) { - return m_Roles.Delete(new string[] { "GroupID", "RoleID" }, + return m_Roles.Delete(new string[] { "GroupID", "RoleID" }, new string[] { groupID.ToString(), roleID.ToString() }); } @@ -365,7 +365,7 @@ namespace OpenSim.Data.PGSQL get { return GetType().Assembly; } } - public PGSqlGroupsGroupsHandler(string connectionString, string realm, string store) + public PGSqlGroupsGroupsHandler(string connectionString, string realm, string store) : base(connectionString, realm, store) { } @@ -380,7 +380,7 @@ namespace OpenSim.Data.PGSQL get { return GetType().Assembly; } } - public PGSqlGroupsMembershipHandler(string connectionString, string realm) + public PGSqlGroupsMembershipHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } @@ -395,7 +395,7 @@ namespace OpenSim.Data.PGSQL get { return GetType().Assembly; } } - public PGSqlGroupsRolesHandler(string connectionString, string realm) + public PGSqlGroupsRolesHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } @@ -410,7 +410,7 @@ namespace OpenSim.Data.PGSQL get { return GetType().Assembly; } } - public PGSqlGroupsRoleMembershipHandler(string connectionString, string realm) + public PGSqlGroupsRoleMembershipHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } @@ -425,7 +425,7 @@ namespace OpenSim.Data.PGSQL get { return GetType().Assembly; } } - public PGSqlGroupsInvitesHandler(string connectionString, string realm) + public PGSqlGroupsInvitesHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } @@ -436,7 +436,7 @@ namespace OpenSim.Data.PGSQL using (NpgsqlCommand cmd = new NpgsqlCommand()) { cmd.CommandText = String.Format("delete from {0} where \"TMStamp\" < CURRENT_DATE - INTERVAL '2 week'", m_Realm); - + ExecuteNonQuery(cmd); } @@ -451,7 +451,7 @@ namespace OpenSim.Data.PGSQL get { return GetType().Assembly; } } - public PGSqlGroupsNoticesHandler(string connectionString, string realm) + public PGSqlGroupsNoticesHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } @@ -462,7 +462,7 @@ namespace OpenSim.Data.PGSQL using (NpgsqlCommand cmd = new NpgsqlCommand()) { cmd.CommandText = String.Format("delete from {0} where \"TMStamp\" < CURRENT_DATE - INTERVAL '2 week'", m_Realm); - + ExecuteNonQuery(cmd); } @@ -477,7 +477,7 @@ namespace OpenSim.Data.PGSQL get { return GetType().Assembly; } } - public PGSqlGroupsPrincipalsHandler(string connectionString, string realm) + public PGSqlGroupsPrincipalsHandler(string connectionString, string realm) : base(connectionString, realm, string.Empty) { } diff --git a/OpenSim/Data/PGSQL/PGSQLInventoryData.cs b/OpenSim/Data/PGSQL/PGSQLInventoryData.cs index c9994332fa..30fc5ea574 100644 --- a/OpenSim/Data/PGSQL/PGSQLInventoryData.cs +++ b/OpenSim/Data/PGSQL/PGSQLInventoryData.cs @@ -69,7 +69,7 @@ namespace OpenSim.Data.PGSQL { m_connectionString = connectionString; database = new PGSQLManager(connectionString); - + //New migrations check of store database.CheckMigration(_migrationStore); } @@ -190,8 +190,8 @@ namespace OpenSim.Data.PGSQL /* NOTE: the implementation below is very inefficient (makes a separate request to get subfolders for * every found folder, recursively). Inventory code for other DBs has been already rewritten to get ALL * inventory for a specific user at once. - * - * Meanwhile, one little thing is corrected: getFolderHierarchy(UUID.Zero) doesn't make sense and should never + * + * Meanwhile, one little thing is corrected: getFolderHierarchy(UUID.Zero) doesn't make sense and should never * be used, so check for that and return an empty list. */ @@ -264,11 +264,11 @@ namespace OpenSim.Data.PGSQL /// Folder to update public void updateInventoryFolder(InventoryFolderBase folder) { - string sql = @"UPDATE inventoryfolders SET ""agentID"" = :agentID, + string sql = @"UPDATE inventoryfolders SET ""agentID"" = :agentID, ""parentFolderID"" = :parentFolderID, ""folderName"" = :folderName, type = :type, - version = :version + version = :version WHERE folderID = :folderID"; string folderName = folder.Name; @@ -337,7 +337,7 @@ namespace OpenSim.Data.PGSQL cmd.Parameters.Add(database.CreateParameter("parentID", UUID.Zero)); conn.Open(); subFolders = getFolderHierarchy(folderID, cmd); - + //Delete all sub-folders foreach (InventoryFolderBase f in subFolders) @@ -403,7 +403,7 @@ namespace OpenSim.Data.PGSQL } } } - + m_log.InfoFormat("[INVENTORY DB]: Found no inventory item with ID : {0}", itemID); return null; } @@ -420,24 +420,24 @@ namespace OpenSim.Data.PGSQL return; } - string sql = @"INSERT INTO inventoryitems - (""inventoryID"", ""assetID"", ""assetType"", ""parentFolderID"", ""avatarID"", ""inventoryName"", + string sql = @"INSERT INTO inventoryitems + (""inventoryID"", ""assetID"", ""assetType"", ""parentFolderID"", ""avatarID"", ""inventoryName"", ""inventoryDescription"", ""inventoryNextPermissions"", ""inventoryCurrentPermissions"", ""invType"", ""creatorID"", ""inventoryBasePermissions"", ""inventoryEveryOnePermissions"", ""inventoryGroupPermissions"", - ""salePrice"", ""SaleType"", ""creationDate"", ""groupID"", ""groupOwned"", flags) + ""salePrice"", ""SaleType"", ""creationDate"", ""groupID"", ""groupOwned"", flags) VALUES (:inventoryID, :assetID, :assetType, :parentFolderID, :avatarID, :inventoryName, :inventoryDescription, :inventoryNextPermissions, :inventoryCurrentPermissions, :invType, :creatorID, :inventoryBasePermissions, :inventoryEveryOnePermissions, :inventoryGroupPermissions, :SalePrice, :SaleType, :creationDate, :groupID, :groupOwned, :flags)"; - + string itemName = item.Name; if (item.Name.Length > 64) { itemName = item.Name.Substring(0, 64); m_log.Warn("[INVENTORY DB]: Name field truncated from " + item.Name.Length.ToString() + " to " + itemName.Length.ToString() + " characters"); } - + string itemDesc = item.Description; if (item.Description.Length > 128) { @@ -502,25 +502,25 @@ namespace OpenSim.Data.PGSQL /// Inventory item to update public void updateInventoryItem(InventoryItemBase item) { - string sql = @"UPDATE inventoryitems SET ""assetID"" = :assetID, + string sql = @"UPDATE inventoryitems SET ""assetID"" = :assetID, ""assetType"" = :assetType, ""parentFolderID"" = :parentFolderID, ""avatarID"" = :avatarID, - ""inventoryName"" = :inventoryName, - ""inventoryDescription"" = :inventoryDescription, - ""inventoryNextPermissions"" = :inventoryNextPermissions, - ""inventoryCurrentPermissions"" = :inventoryCurrentPermissions, - ""invType"" = :invType, - ""creatorID"" = :creatorID, - ""inventoryBasePermissions"" = :inventoryBasePermissions, - ""inventoryEveryOnePermissions"" = :inventoryEveryOnePermissions, - ""inventoryGroupPermissions"" = :inventoryGroupPermissions, - ""salePrice"" = :SalePrice, - ""saleType"" = :SaleType, - ""creationDate"" = :creationDate, - ""groupID"" = :groupID, - ""groupOwned"" = :groupOwned, - flags = :flags + ""inventoryName"" = :inventoryName, + ""inventoryDescription"" = :inventoryDescription, + ""inventoryNextPermissions"" = :inventoryNextPermissions, + ""inventoryCurrentPermissions"" = :inventoryCurrentPermissions, + ""invType"" = :invType, + ""creatorID"" = :creatorID, + ""inventoryBasePermissions"" = :inventoryBasePermissions, + ""inventoryEveryOnePermissions"" = :inventoryEveryOnePermissions, + ""inventoryGroupPermissions"" = :inventoryGroupPermissions, + ""salePrice"" = :SalePrice, + ""saleType"" = :SaleType, + ""creationDate"" = :creationDate, + ""groupID"" = :groupID, + ""groupOwned"" = :groupOwned, + flags = :flags WHERE ""inventoryID"" = :inventoryID"; string itemName = item.Name; @@ -529,7 +529,7 @@ namespace OpenSim.Data.PGSQL itemName = item.Name.Substring(0, 64); m_log.Warn("[INVENTORY DB]: Name field truncated from " + item.Name.Length.ToString() + " to " + itemName.Length.ToString() + " characters on update"); } - + string itemDesc = item.Description; if (item.Description.Length > 128) { diff --git a/OpenSim/Data/PGSQL/PGSQLManager.cs b/OpenSim/Data/PGSQL/PGSQLManager.cs index af5a7cd02d..276a37cbb5 100644 --- a/OpenSim/Data/PGSQL/PGSQLManager.cs +++ b/OpenSim/Data/PGSQL/PGSQLManager.cs @@ -326,7 +326,7 @@ namespace OpenSim.Data.PGSQL /// migrationStore. public void CheckMigration(string migrationStore) { - using (NpgsqlConnection connection = new NpgsqlConnection(connectionString)) + using (NpgsqlConnection connection = new NpgsqlConnection(connectionString)) { connection.Open(); Assembly assem = GetType().Assembly; diff --git a/OpenSim/Data/PGSQL/PGSQLMigration.cs b/OpenSim/Data/PGSQL/PGSQLMigration.cs index 709fde04f2..749a3f2bd0 100644 --- a/OpenSim/Data/PGSQL/PGSQLMigration.cs +++ b/OpenSim/Data/PGSQL/PGSQLMigration.cs @@ -54,8 +54,8 @@ namespace OpenSim.Data.PGSQL { try { - cmd.CommandText = "select version from migrations where name = '" + type + "' " + - " order by version desc limit 1"; //Must be + cmd.CommandText = "select version from migrations where name = '" + type + "' " + + " order by version desc limit 1"; //Must be using (NpgsqlDataReader reader = cmd.ExecuteReader()) { if (reader.Read()) diff --git a/OpenSim/Data/PGSQL/PGSQLOfflineIMData.cs b/OpenSim/Data/PGSQL/PGSQLOfflineIMData.cs index 82e5ed829e..a0c354227a 100644 --- a/OpenSim/Data/PGSQL/PGSQLOfflineIMData.cs +++ b/OpenSim/Data/PGSQL/PGSQLOfflineIMData.cs @@ -47,7 +47,7 @@ namespace OpenSim.Data.PGSQL using (NpgsqlCommand cmd = new NpgsqlCommand()) { cmd.CommandText = String.Format("delete from {0} where \"TMStamp\" < CURRENT_DATE - INTERVAL '2 week'", m_Realm); - + ExecuteNonQuery(cmd); } diff --git a/OpenSim/Data/PGSQL/PGSQLPresenceData.cs b/OpenSim/Data/PGSQL/PGSQLPresenceData.cs index 0376585863..ebbe8d35d1 100755 --- a/OpenSim/Data/PGSQL/PGSQLPresenceData.cs +++ b/OpenSim/Data/PGSQL/PGSQLPresenceData.cs @@ -80,7 +80,7 @@ namespace OpenSim.Data.PGSQL PresenceData[] pd = Get("SessionID", sessionID.ToString()); if (pd.Length == 0) return false; - + if (regionID == UUID.Zero) return false; @@ -103,7 +103,7 @@ namespace OpenSim.Data.PGSQL public bool VerifyAgent(UUID agentId, UUID secureSessionID) { PresenceData[] ret = Get("SecureSessionID", secureSessionID.ToString()); - + if (ret.Length == 0) return false; diff --git a/OpenSim/Data/PGSQL/PGSQLRegionData.cs b/OpenSim/Data/PGSQL/PGSQLRegionData.cs index fc352c3905..1272e37d96 100644 --- a/OpenSim/Data/PGSQL/PGSQLRegionData.cs +++ b/OpenSim/Data/PGSQL/PGSQLRegionData.cs @@ -57,7 +57,7 @@ namespace OpenSim.Data.PGSQL get { return GetType().Assembly; } } - public PGSQLRegionData(string connectionString, string realm) + public PGSQLRegionData(string connectionString, string realm) { m_Realm = realm; m_ConnectionString = connectionString; @@ -77,7 +77,7 @@ namespace OpenSim.Data.PGSQL m_FieldTypes = new Dictionary(); string query = string.Format(@"select column_name,data_type - from INFORMATION_SCHEMA.COLUMNS + from INFORMATION_SCHEMA.COLUMNS where table_name = lower('{0}'); ", m_Realm); @@ -107,7 +107,7 @@ namespace OpenSim.Data.PGSQL using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) { cmd.Parameters.Add(m_database.CreateParameter("regionName", regionName)); - if (scopeID != UUID.Zero) + if (scopeID != UUID.Zero) cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID)); conn.Open(); return RunCommand(cmd); @@ -134,7 +134,7 @@ namespace OpenSim.Data.PGSQL cmd.Parameters.Add(m_database.CreateParameter("startY", startY)); cmd.Parameters.Add(m_database.CreateParameter("endX", endX)); cmd.Parameters.Add(m_database.CreateParameter("endY", endY)); - if (scopeID != UUID.Zero) + if (scopeID != UUID.Zero) cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID)); conn.Open(); ret = RunCommand(cmd); @@ -167,7 +167,7 @@ namespace OpenSim.Data.PGSQL using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) { cmd.Parameters.Add(m_database.CreateParameter("regionID", regionID)); - if (scopeID != UUID.Zero) + if (scopeID != UUID.Zero) cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID)); conn.Open(); List ret = RunCommand(cmd); @@ -196,7 +196,7 @@ namespace OpenSim.Data.PGSQL cmd.Parameters.Add(m_database.CreateParameter("startY", qstartY)); cmd.Parameters.Add(m_database.CreateParameter("endX", endX)); cmd.Parameters.Add(m_database.CreateParameter("endY", endY)); - if (scopeID != UUID.Zero) + if (scopeID != UUID.Zero) cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID)); conn.Open(); @@ -298,7 +298,7 @@ namespace OpenSim.Data.PGSQL { string update = "update " + m_Realm + " set \"locX\"=:posX, \"locY\"=:posY, \"sizeX\"=:sizeX, \"sizeY\"=:sizeY "; - + foreach (string field in fields) { diff --git a/OpenSim/Data/PGSQL/PGSQLSimulationData.cs b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs index 902aae0ae5..33d12bd71e 100755 --- a/OpenSim/Data/PGSQL/PGSQLSimulationData.cs +++ b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs @@ -110,11 +110,11 @@ namespace OpenSim.Data.PGSQL Dictionary objects = new Dictionary(); SceneObjectGroup grp = null; - string sql = @"SELECT *, - CASE WHEN prims.""UUID"" = prims.""SceneGroupID"" THEN 0 ELSE 1 END as sort - FROM prims - LEFT JOIN primshapes ON prims.""UUID"" = primshapes.""UUID"" - WHERE ""RegionUUID"" = :RegionUUID + string sql = @"SELECT *, + CASE WHEN prims.""UUID"" = prims.""SceneGroupID"" THEN 0 ELSE 1 END as sort + FROM prims + LEFT JOIN primshapes ON prims.""UUID"" = primshapes.""UUID"" + WHERE ""RegionUUID"" = :RegionUUID ORDER BY ""SceneGroupID"" asc, sort asc, ""LinkNumber"" asc"; using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) @@ -146,7 +146,7 @@ namespace OpenSim.Data.PGSQL // There sometimes exist OpenSim bugs that 'orphan groups' so that none of the prims are // recorded as the root prim (for which the UUID must equal the persisted group UUID). In // this case, force the UUID to be the same as the group UUID so that at least these can be - // deleted (we need to change the UUID so that any other prims in the linkset can also be + // deleted (we need to change the UUID so that any other prims in the linkset can also be // deleted). if (sceneObjectPart.UUID != groupID && groupID != UUID.Zero) { @@ -178,7 +178,7 @@ namespace OpenSim.Data.PGSQL objects[grp.UUID] = grp; // Instead of attempting to LoadItems on every prim, - // most of which probably have no items... get a + // most of which probably have no items... get a // list from DB of all prims which have items and // LoadItems only on those List primsWithInventory = new List(); @@ -331,52 +331,52 @@ namespace OpenSim.Data.PGSQL private void StoreSceneObjectPrim(SceneObjectPart sceneObjectPart, NpgsqlCommand sqlCommand, UUID sceneGroupID, UUID regionUUID) { //Big query to update or insert a new prim. - + string queryPrims = @" - UPDATE prims SET - ""CreationDate"" = :CreationDate, ""Name"" = :Name, ""Text"" = :Text, ""Description"" = :Description, ""SitName"" = :SitName, - ""TouchName"" = :TouchName, ""ObjectFlags"" = :ObjectFlags, ""OwnerMask"" = :OwnerMask, ""NextOwnerMask"" = :NextOwnerMask, ""GroupMask"" = :GroupMask, - ""EveryoneMask"" = :EveryoneMask, ""BaseMask"" = :BaseMask, ""PositionX"" = :PositionX, ""PositionY"" = :PositionY, ""PositionZ"" = :PositionZ, - ""GroupPositionX"" = :GroupPositionX, ""GroupPositionY"" = :GroupPositionY, ""GroupPositionZ"" = :GroupPositionZ, ""VelocityX"" = :VelocityX, - ""VelocityY"" = :VelocityY, ""VelocityZ"" = :VelocityZ, ""AngularVelocityX"" = :AngularVelocityX, ""AngularVelocityY"" = :AngularVelocityY, - ""AngularVelocityZ"" = :AngularVelocityZ, ""AccelerationX"" = :AccelerationX, ""AccelerationY"" = :AccelerationY, - ""AccelerationZ"" = :AccelerationZ, ""RotationX"" = :RotationX, ""RotationY"" = :RotationY, ""RotationZ"" = :RotationZ, ""RotationW"" = :RotationW, - ""SitTargetOffsetX"" = :SitTargetOffsetX, ""SitTargetOffsetY"" = :SitTargetOffsetY, ""SitTargetOffsetZ"" = :SitTargetOffsetZ, - ""SitTargetOrientW"" = :SitTargetOrientW, ""SitTargetOrientX"" = :SitTargetOrientX, ""SitTargetOrientY"" = :SitTargetOrientY, - ""SitTargetOrientZ"" = :SitTargetOrientZ, ""RegionUUID"" = :RegionUUID, ""CreatorID"" = :CreatorID, ""OwnerID"" = :OwnerID, ""GroupID"" = :GroupID, - ""LastOwnerID"" = :LastOwnerID, ""SceneGroupID"" = :SceneGroupID, ""PayPrice"" = :PayPrice, ""PayButton1"" = :PayButton1, ""PayButton2"" = :PayButton2, - ""PayButton3"" = :PayButton3, ""PayButton4"" = :PayButton4, ""LoopedSound"" = :LoopedSound, ""LoopedSoundGain"" = :LoopedSoundGain, - ""TextureAnimation"" = :TextureAnimation, ""OmegaX"" = :OmegaX, ""OmegaY"" = :OmegaY, ""OmegaZ"" = :OmegaZ, ""CameraEyeOffsetX"" = :CameraEyeOffsetX, - ""CameraEyeOffsetY"" = :CameraEyeOffsetY, ""CameraEyeOffsetZ"" = :CameraEyeOffsetZ, ""CameraAtOffsetX"" = :CameraAtOffsetX, - ""CameraAtOffsetY"" = :CameraAtOffsetY, ""CameraAtOffsetZ"" = :CameraAtOffsetZ, ""ForceMouselook"" = :ForceMouselook, - ""ScriptAccessPin"" = :ScriptAccessPin, ""AllowedDrop"" = :AllowedDrop, ""DieAtEdge"" = :DieAtEdge, ""SalePrice"" = :SalePrice, - ""SaleType"" = :SaleType, ""ColorR"" = :ColorR, ""ColorG"" = :ColorG, ""ColorB"" = :ColorB, ""ColorA"" = :ColorA, ""ParticleSystem"" = :ParticleSystem, + UPDATE prims SET + ""CreationDate"" = :CreationDate, ""Name"" = :Name, ""Text"" = :Text, ""Description"" = :Description, ""SitName"" = :SitName, + ""TouchName"" = :TouchName, ""ObjectFlags"" = :ObjectFlags, ""OwnerMask"" = :OwnerMask, ""NextOwnerMask"" = :NextOwnerMask, ""GroupMask"" = :GroupMask, + ""EveryoneMask"" = :EveryoneMask, ""BaseMask"" = :BaseMask, ""PositionX"" = :PositionX, ""PositionY"" = :PositionY, ""PositionZ"" = :PositionZ, + ""GroupPositionX"" = :GroupPositionX, ""GroupPositionY"" = :GroupPositionY, ""GroupPositionZ"" = :GroupPositionZ, ""VelocityX"" = :VelocityX, + ""VelocityY"" = :VelocityY, ""VelocityZ"" = :VelocityZ, ""AngularVelocityX"" = :AngularVelocityX, ""AngularVelocityY"" = :AngularVelocityY, + ""AngularVelocityZ"" = :AngularVelocityZ, ""AccelerationX"" = :AccelerationX, ""AccelerationY"" = :AccelerationY, + ""AccelerationZ"" = :AccelerationZ, ""RotationX"" = :RotationX, ""RotationY"" = :RotationY, ""RotationZ"" = :RotationZ, ""RotationW"" = :RotationW, + ""SitTargetOffsetX"" = :SitTargetOffsetX, ""SitTargetOffsetY"" = :SitTargetOffsetY, ""SitTargetOffsetZ"" = :SitTargetOffsetZ, + ""SitTargetOrientW"" = :SitTargetOrientW, ""SitTargetOrientX"" = :SitTargetOrientX, ""SitTargetOrientY"" = :SitTargetOrientY, + ""SitTargetOrientZ"" = :SitTargetOrientZ, ""RegionUUID"" = :RegionUUID, ""CreatorID"" = :CreatorID, ""OwnerID"" = :OwnerID, ""GroupID"" = :GroupID, + ""LastOwnerID"" = :LastOwnerID, ""SceneGroupID"" = :SceneGroupID, ""PayPrice"" = :PayPrice, ""PayButton1"" = :PayButton1, ""PayButton2"" = :PayButton2, + ""PayButton3"" = :PayButton3, ""PayButton4"" = :PayButton4, ""LoopedSound"" = :LoopedSound, ""LoopedSoundGain"" = :LoopedSoundGain, + ""TextureAnimation"" = :TextureAnimation, ""OmegaX"" = :OmegaX, ""OmegaY"" = :OmegaY, ""OmegaZ"" = :OmegaZ, ""CameraEyeOffsetX"" = :CameraEyeOffsetX, + ""CameraEyeOffsetY"" = :CameraEyeOffsetY, ""CameraEyeOffsetZ"" = :CameraEyeOffsetZ, ""CameraAtOffsetX"" = :CameraAtOffsetX, + ""CameraAtOffsetY"" = :CameraAtOffsetY, ""CameraAtOffsetZ"" = :CameraAtOffsetZ, ""ForceMouselook"" = :ForceMouselook, + ""ScriptAccessPin"" = :ScriptAccessPin, ""AllowedDrop"" = :AllowedDrop, ""DieAtEdge"" = :DieAtEdge, ""SalePrice"" = :SalePrice, + ""SaleType"" = :SaleType, ""ColorR"" = :ColorR, ""ColorG"" = :ColorG, ""ColorB"" = :ColorB, ""ColorA"" = :ColorA, ""ParticleSystem"" = :ParticleSystem, ""ClickAction"" = :ClickAction, ""Material"" = :Material, ""CollisionSound"" = :CollisionSound, ""CollisionSoundVolume"" = :CollisionSoundVolume, ""PassTouches"" = :PassTouches, ""LinkNumber"" = :LinkNumber, ""MediaURL"" = :MediaURL, ""DynAttrs"" = :DynAttrs, ""PhysicsShapeType"" = :PhysicsShapeType, ""Density"" = :Density, ""GravityModifier"" = :GravityModifier, ""Friction"" = :Friction, ""Restitution"" = :Restitution WHERE ""UUID"" = :UUID ; - INSERT INTO + INSERT INTO prims ( ""UUID"", ""CreationDate"", ""Name"", ""Text"", ""Description"", ""SitName"", ""TouchName"", ""ObjectFlags"", ""OwnerMask"", ""NextOwnerMask"", ""GroupMask"", - ""EveryoneMask"", ""BaseMask"", ""PositionX"", ""PositionY"", ""PositionZ"", ""GroupPositionX"", ""GroupPositionY"", ""GroupPositionZ"", ""VelocityX"", - ""VelocityY"", ""VelocityZ"", ""AngularVelocityX"", ""AngularVelocityY"", ""AngularVelocityZ"", ""AccelerationX"", ""AccelerationY"", ""AccelerationZ"", - ""RotationX"", ""RotationY"", ""RotationZ"", ""RotationW"", ""SitTargetOffsetX"", ""SitTargetOffsetY"", ""SitTargetOffsetZ"", ""SitTargetOrientW"", - ""SitTargetOrientX"", ""SitTargetOrientY"", ""SitTargetOrientZ"", ""RegionUUID"", ""CreatorID"", ""OwnerID"", ""GroupID"", ""LastOwnerID"", ""SceneGroupID"", - ""PayPrice"", ""PayButton1"", ""PayButton2"", ""PayButton3"", ""PayButton4"", ""LoopedSound"", ""LoopedSoundGain"", ""TextureAnimation"", ""OmegaX"", - ""OmegaY"", ""OmegaZ"", ""CameraEyeOffsetX"", ""CameraEyeOffsetY"", ""CameraEyeOffsetZ"", ""CameraAtOffsetX"", ""CameraAtOffsetY"", ""CameraAtOffsetZ"", - ""ForceMouselook"", ""ScriptAccessPin"", ""AllowedDrop"", ""DieAtEdge"", ""SalePrice"", ""SaleType"", ""ColorR"", ""ColorG"", ""ColorB"", ""ColorA"", + ""EveryoneMask"", ""BaseMask"", ""PositionX"", ""PositionY"", ""PositionZ"", ""GroupPositionX"", ""GroupPositionY"", ""GroupPositionZ"", ""VelocityX"", + ""VelocityY"", ""VelocityZ"", ""AngularVelocityX"", ""AngularVelocityY"", ""AngularVelocityZ"", ""AccelerationX"", ""AccelerationY"", ""AccelerationZ"", + ""RotationX"", ""RotationY"", ""RotationZ"", ""RotationW"", ""SitTargetOffsetX"", ""SitTargetOffsetY"", ""SitTargetOffsetZ"", ""SitTargetOrientW"", + ""SitTargetOrientX"", ""SitTargetOrientY"", ""SitTargetOrientZ"", ""RegionUUID"", ""CreatorID"", ""OwnerID"", ""GroupID"", ""LastOwnerID"", ""SceneGroupID"", + ""PayPrice"", ""PayButton1"", ""PayButton2"", ""PayButton3"", ""PayButton4"", ""LoopedSound"", ""LoopedSoundGain"", ""TextureAnimation"", ""OmegaX"", + ""OmegaY"", ""OmegaZ"", ""CameraEyeOffsetX"", ""CameraEyeOffsetY"", ""CameraEyeOffsetZ"", ""CameraAtOffsetX"", ""CameraAtOffsetY"", ""CameraAtOffsetZ"", + ""ForceMouselook"", ""ScriptAccessPin"", ""AllowedDrop"", ""DieAtEdge"", ""SalePrice"", ""SaleType"", ""ColorR"", ""ColorG"", ""ColorB"", ""ColorA"", ""ParticleSystem"", ""ClickAction"", ""Material"", ""CollisionSound"", ""CollisionSoundVolume"", ""PassTouches"", ""LinkNumber"", ""MediaURL"", ""DynAttrs"", ""PhysicsShapeType"", ""Density"", ""GravityModifier"", ""Friction"", ""Restitution"" - ) Select - :UUID, :CreationDate, :Name, :Text, :Description, :SitName, :TouchName, :ObjectFlags, :OwnerMask, :NextOwnerMask, :GroupMask, - :EveryoneMask, :BaseMask, :PositionX, :PositionY, :PositionZ, :GroupPositionX, :GroupPositionY, :GroupPositionZ, :VelocityX, - :VelocityY, :VelocityZ, :AngularVelocityX, :AngularVelocityY, :AngularVelocityZ, :AccelerationX, :AccelerationY, :AccelerationZ, - :RotationX, :RotationY, :RotationZ, :RotationW, :SitTargetOffsetX, :SitTargetOffsetY, :SitTargetOffsetZ, :SitTargetOrientW, - :SitTargetOrientX, :SitTargetOrientY, :SitTargetOrientZ, :RegionUUID, :CreatorID, :OwnerID, :GroupID, :LastOwnerID, :SceneGroupID, - :PayPrice, :PayButton1, :PayButton2, :PayButton3, :PayButton4, :LoopedSound, :LoopedSoundGain, :TextureAnimation, :OmegaX, - :OmegaY, :OmegaZ, :CameraEyeOffsetX, :CameraEyeOffsetY, :CameraEyeOffsetZ, :CameraAtOffsetX, :CameraAtOffsetY, :CameraAtOffsetZ, - :ForceMouselook, :ScriptAccessPin, :AllowedDrop, :DieAtEdge, :SalePrice, :SaleType, :ColorR, :ColorG, :ColorB, :ColorA, + ) Select + :UUID, :CreationDate, :Name, :Text, :Description, :SitName, :TouchName, :ObjectFlags, :OwnerMask, :NextOwnerMask, :GroupMask, + :EveryoneMask, :BaseMask, :PositionX, :PositionY, :PositionZ, :GroupPositionX, :GroupPositionY, :GroupPositionZ, :VelocityX, + :VelocityY, :VelocityZ, :AngularVelocityX, :AngularVelocityY, :AngularVelocityZ, :AccelerationX, :AccelerationY, :AccelerationZ, + :RotationX, :RotationY, :RotationZ, :RotationW, :SitTargetOffsetX, :SitTargetOffsetY, :SitTargetOffsetZ, :SitTargetOrientW, + :SitTargetOrientX, :SitTargetOrientY, :SitTargetOrientZ, :RegionUUID, :CreatorID, :OwnerID, :GroupID, :LastOwnerID, :SceneGroupID, + :PayPrice, :PayButton1, :PayButton2, :PayButton3, :PayButton4, :LoopedSound, :LoopedSoundGain, :TextureAnimation, :OmegaX, + :OmegaY, :OmegaZ, :CameraEyeOffsetX, :CameraEyeOffsetY, :CameraEyeOffsetZ, :CameraAtOffsetX, :CameraAtOffsetY, :CameraAtOffsetZ, + :ForceMouselook, :ScriptAccessPin, :AllowedDrop, :DieAtEdge, :SalePrice, :SaleType, :ColorR, :ColorG, :ColorB, :ColorA, :ParticleSystem, :ClickAction, :Material, :CollisionSound, :CollisionSoundVolume, :PassTouches, :LinkNumber, :MediaURL, :DynAttrs, :PhysicsShapeType, :Density, :GravityModifier, :Friction, :Restitution where not EXISTS (SELECT ""UUID"" FROM prims WHERE ""UUID"" = :UUID); @@ -401,26 +401,26 @@ namespace OpenSim.Data.PGSQL private void StoreSceneObjectPrimShapes(SceneObjectPart sceneObjectPart, NpgsqlCommand sqlCommand, UUID sceneGroupID, UUID regionUUID) { //Big query to or insert or update primshapes - + string queryPrimShapes = @" - UPDATE primshapes SET - ""Shape"" = :Shape, ""ScaleX"" = :ScaleX, ""ScaleY"" = :ScaleY, ""ScaleZ"" = :ScaleZ, ""PCode"" = :PCode, ""PathBegin"" = :PathBegin, - ""PathEnd"" = :PathEnd, ""PathScaleX"" = :PathScaleX, ""PathScaleY"" = :PathScaleY, ""PathShearX"" = :PathShearX, ""PathShearY"" = :PathShearY, - ""PathSkew"" = :PathSkew, ""PathCurve"" = :PathCurve, ""PathRadiusOffset"" = :PathRadiusOffset, ""PathRevolutions"" = :PathRevolutions, - ""PathTaperX"" = :PathTaperX, ""PathTaperY"" = :PathTaperY, ""PathTwist"" = :PathTwist, ""PathTwistBegin"" = :PathTwistBegin, - ""ProfileBegin"" = :ProfileBegin, ""ProfileEnd"" = :ProfileEnd, ""ProfileCurve"" = :ProfileCurve, ""ProfileHollow"" = :ProfileHollow, + UPDATE primshapes SET + ""Shape"" = :Shape, ""ScaleX"" = :ScaleX, ""ScaleY"" = :ScaleY, ""ScaleZ"" = :ScaleZ, ""PCode"" = :PCode, ""PathBegin"" = :PathBegin, + ""PathEnd"" = :PathEnd, ""PathScaleX"" = :PathScaleX, ""PathScaleY"" = :PathScaleY, ""PathShearX"" = :PathShearX, ""PathShearY"" = :PathShearY, + ""PathSkew"" = :PathSkew, ""PathCurve"" = :PathCurve, ""PathRadiusOffset"" = :PathRadiusOffset, ""PathRevolutions"" = :PathRevolutions, + ""PathTaperX"" = :PathTaperX, ""PathTaperY"" = :PathTaperY, ""PathTwist"" = :PathTwist, ""PathTwistBegin"" = :PathTwistBegin, + ""ProfileBegin"" = :ProfileBegin, ""ProfileEnd"" = :ProfileEnd, ""ProfileCurve"" = :ProfileCurve, ""ProfileHollow"" = :ProfileHollow, ""Texture"" = :Texture, ""ExtraParams"" = :ExtraParams, ""State"" = :State, ""Media"" = :Media WHERE ""UUID"" = :UUID ; - INSERT INTO + INSERT INTO primshapes ( - ""UUID"", ""Shape"", ""ScaleX"", ""ScaleY"", ""ScaleZ"", ""PCode"", ""PathBegin"", ""PathEnd"", ""PathScaleX"", ""PathScaleY"", ""PathShearX"", ""PathShearY"", - ""PathSkew"", ""PathCurve"", ""PathRadiusOffset"", ""PathRevolutions"", ""PathTaperX"", ""PathTaperY"", ""PathTwist"", ""PathTwistBegin"", ""ProfileBegin"", + ""UUID"", ""Shape"", ""ScaleX"", ""ScaleY"", ""ScaleZ"", ""PCode"", ""PathBegin"", ""PathEnd"", ""PathScaleX"", ""PathScaleY"", ""PathShearX"", ""PathShearY"", + ""PathSkew"", ""PathCurve"", ""PathRadiusOffset"", ""PathRevolutions"", ""PathTaperX"", ""PathTaperY"", ""PathTwist"", ""PathTwistBegin"", ""ProfileBegin"", ""ProfileEnd"", ""ProfileCurve"", ""ProfileHollow"", ""Texture"", ""ExtraParams"", ""State"", ""Media"" - ) + ) Select - :UUID, :Shape, :ScaleX, :ScaleY, :ScaleZ, :PCode, :PathBegin, :PathEnd, :PathScaleX, :PathScaleY, :PathShearX, :PathShearY, - :PathSkew, :PathCurve, :PathRadiusOffset, :PathRevolutions, :PathTaperX, :PathTaperY, :PathTwist, :PathTwistBegin, :ProfileBegin, + :UUID, :Shape, :ScaleX, :ScaleY, :ScaleZ, :PCode, :PathBegin, :PathEnd, :PathScaleX, :PathScaleY, :PathShearX, :PathShearY, + :PathSkew, :PathCurve, :PathRadiusOffset, :PathRevolutions, :PathTaperX, :PathTaperY, :PathTwist, :PathTwistBegin, :ProfileBegin, :ProfileEnd, :ProfileCurve, :ProfileHollow, :Texture, :ExtraParams, :State, :Media where not EXISTS (SELECT ""UUID"" FROM primshapes WHERE ""UUID"" = :UUID); "; @@ -500,7 +500,7 @@ namespace OpenSim.Data.PGSQL sql = @"INSERT INTO primitems ( ""itemID"",""primID"",""assetID"",""parentFolderID"",""invType"",""assetType"",""name"",""description"",""creationDate"",""creatorID"",""ownerID"",""lastOwnerID"",""groupID"", - ""nextPermissions"",""currentPermissions"",""basePermissions"",""everyonePermissions"",""groupPermissions"",""flags"") + ""nextPermissions"",""currentPermissions"",""basePermissions"",""everyonePermissions"",""groupPermissions"",""flags"") VALUES (:itemID,:primID,:assetID,:parentFolderID,:invType,:assetType,:name,:description,:creationDate,:creatorID,:ownerID, :lastOwnerID,:groupID,:nextPermissions,:currentPermissions,:basePermissions,:everyonePermissions,:groupPermissions,:flags)"; @@ -538,7 +538,7 @@ namespace OpenSim.Data.PGSQL { TerrainData terrData = null; - string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from terrain + string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from terrain where ""RegionUUID"" = :RegionUUID order by ""Revision"" desc limit 1; "; using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) @@ -577,7 +577,7 @@ namespace OpenSim.Data.PGSQL { TerrainData terrData = null; - string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from bakedterrain + string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from bakedterrain where ""RegionUUID"" = :RegionUUID; "; using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) @@ -1319,7 +1319,7 @@ namespace OpenSim.Data.PGSQL { { string sql = "DELETE FROM regionenvironment WHERE region_id = :region_id ;"; - + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) { @@ -1420,17 +1420,17 @@ namespace OpenSim.Data.PGSQL { //This method only updates region settings!!! First call LoadRegionSettings to create new region settings in DB sql = - @"UPDATE regionsettings SET block_terraform = :block_terraform ,block_fly = :block_fly ,allow_damage = :allow_damage -,restrict_pushing = :restrict_pushing ,allow_land_resell = :allow_land_resell ,allow_land_join_divide = :allow_land_join_divide -,block_show_in_search = :block_show_in_search ,agent_limit = :agent_limit ,object_bonus = :object_bonus ,maturity = :maturity -,disable_scripts = :disable_scripts ,disable_collisions = :disable_collisions ,disable_physics = :disable_physics -,terrain_texture_1 = :terrain_texture_1 ,terrain_texture_2 = :terrain_texture_2 ,terrain_texture_3 = :terrain_texture_3 -,terrain_texture_4 = :terrain_texture_4 ,elevation_1_nw = :elevation_1_nw ,elevation_2_nw = :elevation_2_nw -,elevation_1_ne = :elevation_1_ne ,elevation_2_ne = :elevation_2_ne ,elevation_1_se = :elevation_1_se ,elevation_2_se = :elevation_2_se -,elevation_1_sw = :elevation_1_sw ,elevation_2_sw = :elevation_2_sw ,water_height = :water_height ,terrain_raise_limit = :terrain_raise_limit -,terrain_lower_limit = :terrain_lower_limit ,use_estate_sun = :use_estate_sun ,fixed_sun = :fixed_sun ,sun_position = :sun_position -,covenant = :covenant ,covenant_datetime = :covenant_datetime, sunvectorx = :sunvectorx, sunvectory = :sunvectory, sunvectorz = :sunvectorz, -""Sandbox"" = :Sandbox, loaded_creation_datetime = :loaded_creation_datetime, loaded_creation_id = :loaded_creation_id, ""map_tile_ID"" = :TerrainImageID, + @"UPDATE regionsettings SET block_terraform = :block_terraform ,block_fly = :block_fly ,allow_damage = :allow_damage +,restrict_pushing = :restrict_pushing ,allow_land_resell = :allow_land_resell ,allow_land_join_divide = :allow_land_join_divide +,block_show_in_search = :block_show_in_search ,agent_limit = :agent_limit ,object_bonus = :object_bonus ,maturity = :maturity +,disable_scripts = :disable_scripts ,disable_collisions = :disable_collisions ,disable_physics = :disable_physics +,terrain_texture_1 = :terrain_texture_1 ,terrain_texture_2 = :terrain_texture_2 ,terrain_texture_3 = :terrain_texture_3 +,terrain_texture_4 = :terrain_texture_4 ,elevation_1_nw = :elevation_1_nw ,elevation_2_nw = :elevation_2_nw +,elevation_1_ne = :elevation_1_ne ,elevation_2_ne = :elevation_2_ne ,elevation_1_se = :elevation_1_se ,elevation_2_se = :elevation_2_se +,elevation_1_sw = :elevation_1_sw ,elevation_2_sw = :elevation_2_sw ,water_height = :water_height ,terrain_raise_limit = :terrain_raise_limit +,terrain_lower_limit = :terrain_lower_limit ,use_estate_sun = :use_estate_sun ,fixed_sun = :fixed_sun ,sun_position = :sun_position +,covenant = :covenant ,covenant_datetime = :covenant_datetime, sunvectorx = :sunvectorx, sunvectory = :sunvectory, sunvectorz = :sunvectorz, +""Sandbox"" = :Sandbox, loaded_creation_datetime = :loaded_creation_datetime, loaded_creation_id = :loaded_creation_id, ""map_tile_ID"" = :TerrainImageID, ""TelehubObject"" = :telehubobject, ""parcel_tile_ID"" = :ParcelImageID WHERE ""regionUUID"" = :regionUUID"; @@ -1465,13 +1465,13 @@ namespace OpenSim.Data.PGSQL elevation_2_ne,elevation_1_se,elevation_2_se,elevation_1_sw,elevation_2_sw,water_height,terrain_raise_limit, terrain_lower_limit,use_estate_sun,fixed_sun,sun_position,covenant,covenant_datetime,sunvectorx, sunvectory, sunvectorz, ""Sandbox"", loaded_creation_datetime, loaded_creation_id - ) + ) VALUES (:regionUUID,:block_terraform,:block_fly,:allow_damage,:restrict_pushing,:allow_land_resell,:allow_land_join_divide, :block_show_in_search,:agent_limit,:object_bonus,:maturity,:disable_scripts,:disable_collisions,:disable_physics, :terrain_texture_1,:terrain_texture_2,:terrain_texture_3,:terrain_texture_4,:elevation_1_nw,:elevation_2_nw,:elevation_1_ne, :elevation_2_ne,:elevation_1_se,:elevation_2_se,:elevation_1_sw,:elevation_2_sw,:water_height,:terrain_raise_limit, - :terrain_lower_limit,:use_estate_sun,:fixed_sun,:sun_position,:covenant, :covenant_datetime, :sunvectorx,:sunvectory, + :terrain_lower_limit,:use_estate_sun,:fixed_sun,:sun_position,:covenant, :covenant_datetime, :sunvectorx,:sunvectory, :sunvectorz, :Sandbox, :loaded_creation_datetime, :loaded_creation_id )"; using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) @@ -1626,7 +1626,7 @@ namespace OpenSim.Data.PGSQL newData.MediaLoop = Convert.ToBoolean(row["MediaLoop"]); newData.ObscureMusic = Convert.ToBoolean(row["ObscureMusic"]); newData.ObscureMedia = Convert.ToBoolean(row["ObscureMedia"]); - + newData.SeeAVs = Convert.ToBoolean(row["SeeAVs"]); newData.AnyAVSounds = Convert.ToBoolean(row["AnyAVSounds"]); newData.GroupAVSounds = Convert.ToBoolean(row["GroupAVSounds"]); @@ -1789,7 +1789,7 @@ namespace OpenSim.Data.PGSQL if (!(primRow["DynAttrs"] is System.DBNull) && (string)primRow["DynAttrs"] != "") prim.DynAttrs = DAMap.FromXml((string)primRow["DynAttrs"]); else - prim.DynAttrs = new DAMap(); + prim.DynAttrs = new DAMap(); prim.PhysicsShapeType = Convert.ToByte(primRow["PhysicsShapeType"]); prim.Density = Convert.ToSingle(primRow["Density"]); @@ -2195,17 +2195,17 @@ namespace OpenSim.Data.PGSQL parameters.Add(_Database.CreateParameter("CollisionSound", prim.CollisionSound)); parameters.Add(_Database.CreateParameter("CollisionSoundVolume", prim.CollisionSoundVolume)); - + parameters.Add(_Database.CreateParameter("PassTouches", prim.PassTouches)); parameters.Add(_Database.CreateParameter("LinkNumber", prim.LinkNum)); parameters.Add(_Database.CreateParameter("MediaURL", prim.MediaUrl)); - + if (prim.DynAttrs.CountNamespaces > 0) parameters.Add(_Database.CreateParameter("DynAttrs", prim.DynAttrs.ToXml())); else parameters.Add(_Database.CreateParameter("DynAttrs", null)); - + parameters.Add(_Database.CreateParameter("PhysicsShapeType", prim.PhysicsShapeType)); parameters.Add(_Database.CreateParameter("Density", (double)prim.Density)); parameters.Add(_Database.CreateParameter("GravityModifier", (double)prim.GravityModifier)); diff --git a/OpenSim/Data/PGSQL/PGSQLUserAccountData.cs b/OpenSim/Data/PGSQL/PGSQLUserAccountData.cs index a2b5a2aa52..64cfff03b1 100644 --- a/OpenSim/Data/PGSQL/PGSQLUserAccountData.cs +++ b/OpenSim/Data/PGSQL/PGSQLUserAccountData.cs @@ -42,13 +42,13 @@ namespace OpenSim.Data.PGSQL { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + public PGSQLUserAccountData(string connectionString, string realm) : base(connectionString, realm, "UserAccount") { } - - /* + + /* private string m_Realm; private List m_ColumnNames = null; private PGSQLManager m_database; @@ -122,7 +122,7 @@ namespace OpenSim.Data.PGSQL { cmd.Parameters.Add(m_database.CreateParameter("principalID", principalID)); cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID)); - + conn.Open(); using (NpgsqlDataReader result = cmd.ExecuteReader()) { @@ -158,8 +158,8 @@ namespace OpenSim.Data.PGSQL } return null; } - - + + public override bool Store(UserAccountData data) { if (data.Data.ContainsKey("PrincipalID")) @@ -214,7 +214,7 @@ namespace OpenSim.Data.PGSQL catch (Exception e){ m_log.ErrorFormat("[USER]: ERROR opened update user {0} ", e.Message); } - + if (conta < 1) { @@ -242,14 +242,14 @@ namespace OpenSim.Data.PGSQL } return true; } - + public bool Store(UserAccountData data, UUID principalID, string token) { return false; } - + public bool SetDataItem(UUID principalID, string item, string value) { string sql = string.Format(@"update {0} set {1} = :{1} where ""UUID"" = :UUID", m_Realm, item); @@ -299,7 +299,7 @@ namespace OpenSim.Data.PGSQL string sql = ""; UUID scope_id; - UUID.TryParse(scopeID.ToString(), out scope_id); + UUID.TryParse(scopeID.ToString(), out scope_id); using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) using (NpgsqlCommand cmd = new NpgsqlCommand()) diff --git a/OpenSim/Data/PGSQL/PGSQLUserProfilesData.cs b/OpenSim/Data/PGSQL/PGSQLUserProfilesData.cs index f1669766af..75a51e2de1 100644 --- a/OpenSim/Data/PGSQL/PGSQLUserProfilesData.cs +++ b/OpenSim/Data/PGSQL/PGSQLUserProfilesData.cs @@ -412,15 +412,15 @@ namespace OpenSim.Data.PGSQL query = @"WITH upsert AS ( UPDATE userpicks SET pickuuid = :PickId, creatoruuid = :CreatorId, toppick = :TopPick, parceluuid = :ParcelId, - name = :Name, description = :Desc, snapshotuuid = :SnapshotId, ""user"" = :User, - originalname = :Original, simname = :SimName, posglobal = :GlobalPos, - sortorder = :SortOrder, enabled = :Enabled - RETURNING * ) + name = :Name, description = :Desc, snapshotuuid = :SnapshotId, ""user"" = :User, + originalname = :Original, simname = :SimName, posglobal = :GlobalPos, + sortorder = :SortOrder, enabled = :Enabled + RETURNING * ) INSERT INTO userpicks (pickuuid,creatoruuid,toppick,parceluuid,name,description, - snapshotuuid,""user"",originalname,simname,posglobal,sortorder,enabled) + snapshotuuid,""user"",originalname,simname,posglobal,sortorder,enabled) SELECT :PickId,:CreatorId,:TopPick,:ParcelId,:Name,:Desc,:SnapshotId,:User, - :Original,:SimName,:GlobalPos,:SortOrder,:Enabled + :Original,:SimName,:GlobalPos,:SortOrder,:Enabled WHERE NOT EXISTS ( SELECT * FROM upsert )"; diff --git a/OpenSim/Data/PGSQL/PGSQLXAssetData.cs b/OpenSim/Data/PGSQL/PGSQLXAssetData.cs index d3518cf536..6e884898f5 100644 --- a/OpenSim/Data/PGSQL/PGSQLXAssetData.cs +++ b/OpenSim/Data/PGSQL/PGSQLXAssetData.cs @@ -141,7 +141,7 @@ namespace OpenSim.Data.PGSQL using (NpgsqlCommand cmd = new NpgsqlCommand( @"SELECT name, description, access_time, ""AssetType"", local, temporary, asset_flags, creatorid, data - FROM XAssetsMeta + FROM XAssetsMeta JOIN XAssetsData ON XAssetsMeta.hash = XAssetsData.Hash WHERE id=:ID", dbcon)) { @@ -179,7 +179,7 @@ namespace OpenSim.Data.PGSQL WebUtil.CopyStream(decompressionStream, outputStream, int.MaxValue); // int compressedLength = asset.Data.Length; asset.Data = outputStream.ToArray(); - + // m_log.DebugFormat( // "[XASSET DB]: Decompressed {0} {1} to {2} bytes from {3}", // asset.ID, asset.Name, asset.Data.Length, compressedLength); @@ -223,16 +223,16 @@ namespace OpenSim.Data.PGSQL { assetName = asset.Name.Substring(0, 64); m_log.WarnFormat( - "[XASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", + "[XASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", asset.Name, asset.ID, asset.Name.Length, assetName.Length); } - + string assetDescription = asset.Description; if (asset.Description.Length > 64) { assetDescription = asset.Description.Substring(0, 64); m_log.WarnFormat( - "[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + "[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); } @@ -268,8 +268,8 @@ namespace OpenSim.Data.PGSQL where not exists( Select id from XAssetsMeta where id = :ID); update XAssetsMeta - set id = :ID, hash = :Hash, name = :Name, description = :Description, - ""AssetType"" = :AssetType, local = :Local, temporary = :Temporary, create_time = :CreateTime, + set id = :ID, hash = :Hash, name = :Name, description = :Description, + ""AssetType"" = :AssetType, local = :Local, temporary = :Temporary, create_time = :CreateTime, access_time = :AccessTime, asset_flags = :AssetFlags, creatorid = :CreatorID where id = :ID; ", @@ -321,13 +321,13 @@ namespace OpenSim.Data.PGSQL { m_log.ErrorFormat("[XASSET DB]: PGSQL failure creating asset data {0} with name \"{1}\". Error: {2}", asset.FullID, asset.Name, e.Message); - + transaction.Rollback(); - + return; } } - + transaction.Commit(); } } @@ -374,7 +374,7 @@ namespace OpenSim.Data.PGSQL catch (Exception e) { m_log.ErrorFormat( - "[XASSET PGSQL DB]: Failure updating access_time for asset {0} with name {1} : {2}", + "[XASSET PGSQL DB]: Failure updating access_time for asset {0} with name {1} : {2}", assetMetadata.ID, assetMetadata.Name, e.Message); } } @@ -519,7 +519,7 @@ namespace OpenSim.Data.PGSQL { dbcon.Open(); using(NpgsqlCommand cmd = new NpgsqlCommand(@"SELECT name, description, access_time, ""AssetType"", temporary, id, asset_flags, creatorid - FROM XAssetsMeta + FROM XAssetsMeta LIMIT :start, :count",dbcon)) { cmd.Parameters.Add(m_database.CreateParameter("start",start)); diff --git a/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs b/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs index 959c2cf393..55a1996f51 100644 --- a/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs +++ b/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs @@ -197,16 +197,16 @@ namespace OpenSim.Data.PGSQL using (NpgsqlCommand cmd = new NpgsqlCommand()) { /* - cmd.CommandText = String.Format(@"select bit_or(""inventoryCurrentPermissions"") as ""inventoryCurrentPermissions"" - from inventoryitems - where ""avatarID"" = :PrincipalID - and ""assetID"" = :AssetID + cmd.CommandText = String.Format(@"select bit_or(""inventoryCurrentPermissions"") as ""inventoryCurrentPermissions"" + from inventoryitems + where ""avatarID"" = :PrincipalID + and ""assetID"" = :AssetID group by ""assetID"" ", m_Realm); */ - cmd.CommandText = String.Format(@"select bit_or(""inventoryCurrentPermissions"") as ""inventoryCurrentPermissions"" - from inventoryitems + cmd.CommandText = String.Format(@"select bit_or(""inventoryCurrentPermissions"") as ""inventoryCurrentPermissions"" + from inventoryitems where ""avatarID""::uuid = :PrincipalID - and ""assetID"" = :AssetID + and ""assetID"" = :AssetID group by ""assetID"" "); cmd.Parameters.Add(m_database.CreateParameter("PrincipalID", principalID)); diff --git a/OpenSim/Data/SQLite/SQLiteAssetData.cs b/OpenSim/Data/SQLite/SQLiteAssetData.cs index 9c2bd2e46e..966d0b8bea 100644 --- a/OpenSim/Data/SQLite/SQLiteAssetData.cs +++ b/OpenSim/Data/SQLite/SQLiteAssetData.cs @@ -138,7 +138,7 @@ namespace OpenSim.Data.SQLite { assetName = asset.Name.Substring(0, AssetBase.MAX_ASSET_NAME); m_log.WarnFormat( - "[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", + "[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", asset.Name, asset.ID, asset.Name.Length, assetName.Length); } @@ -147,7 +147,7 @@ namespace OpenSim.Data.SQLite { assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); m_log.WarnFormat( - "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); } diff --git a/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs b/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs index 0428c11f76..8fb955c799 100644 --- a/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs +++ b/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs @@ -45,7 +45,7 @@ namespace OpenSim.Data.SQLite public class SQLiteAuthenticationData : SQLiteFramework, IAuthenticationData { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private string m_Realm; private List m_ColumnNames; private int m_LastExpire; @@ -223,7 +223,7 @@ namespace OpenSim.Data.SQLite if (System.Environment.TickCount - m_LastExpire > 30000) DoExpire(); - using (SqliteCommand cmd = new SqliteCommand("insert into tokens (UUID, token, validity) values ('" + principalID.ToString() + + using (SqliteCommand cmd = new SqliteCommand("insert into tokens (UUID, token, validity) values ('" + principalID.ToString() + "', '" + token + "', datetime('now', 'localtime', '+" + lifetime.ToString() + " minutes'))")) { if (ExecuteNonQuery(cmd, m_Connection) > 0) @@ -238,7 +238,7 @@ namespace OpenSim.Data.SQLite if (System.Environment.TickCount - m_LastExpire > 30000) DoExpire(); - using (SqliteCommand cmd = new SqliteCommand("update tokens set validity = datetime('now', 'localtime', '+" + lifetime.ToString() + + using (SqliteCommand cmd = new SqliteCommand("update tokens set validity = datetime('now', 'localtime', '+" + lifetime.ToString() + " minutes') where UUID = '" + principalID.ToString() + "' and token = '" + token + "' and validity > datetime('now', 'localtime')")) { if (ExecuteNonQuery(cmd, m_Connection) > 0) diff --git a/OpenSim/Data/SQLite/SQLiteEstateData.cs b/OpenSim/Data/SQLite/SQLiteEstateData.cs index d51f2d413d..0fcab21824 100644 --- a/OpenSim/Data/SQLite/SQLiteEstateData.cs +++ b/OpenSim/Data/SQLite/SQLiteEstateData.cs @@ -190,7 +190,7 @@ namespace OpenSim.Data.SQLite IDataReader r = null; using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) - { + { names.Remove("EstateID"); string sql = "insert into estate_settings ("+String.Join(",", names.ToArray())+") values ( :"+String.Join(", :", names.ToArray())+")"; @@ -386,15 +386,15 @@ namespace OpenSim.Data.SQLite return DoLoad(cmd, UUID.Zero, false); } } - + public List LoadEstateSettingsAll() { List estateSettings = new List(); - + List estateIds = GetEstatesAll(); foreach (int estateId in estateIds) estateSettings.Add(LoadEstateSettings(estateId)); - + return estateSettings; } @@ -421,7 +421,7 @@ namespace OpenSim.Data.SQLite return result; } - + public List GetEstatesAll() { List result = new List(); @@ -442,7 +442,7 @@ namespace OpenSim.Data.SQLite } r.Close(); - return result; + return result; } public List GetEstatesByOwner(UUID ownerID) diff --git a/OpenSim/Data/SQLite/SQLiteGenericTableHandler.cs b/OpenSim/Data/SQLite/SQLiteGenericTableHandler.cs index 9fbeb100ce..a4b84b1d15 100644 --- a/OpenSim/Data/SQLite/SQLiteGenericTableHandler.cs +++ b/OpenSim/Data/SQLite/SQLiteGenericTableHandler.cs @@ -189,7 +189,7 @@ namespace OpenSim.Data.SQLite m_Fields[name].SetValue(row, reader[name]); } } - + if (m_DataField != null) { Dictionary data = @@ -268,7 +268,7 @@ namespace OpenSim.Data.SQLite public virtual bool Delete(string field, string key) { return Delete(new string[] { field }, new string[] { key }); - } + } public virtual bool Delete(string[] fields, string[] keys) { diff --git a/OpenSim/Data/SQLite/SQLiteGridUserData.cs b/OpenSim/Data/SQLite/SQLiteGridUserData.cs index d8c52f8880..987240cd5a 100644 --- a/OpenSim/Data/SQLite/SQLiteGridUserData.cs +++ b/OpenSim/Data/SQLite/SQLiteGridUserData.cs @@ -43,7 +43,7 @@ namespace OpenSim.Data.SQLite { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - public SQLiteGridUserData(string connectionString, string realm) + public SQLiteGridUserData(string connectionString, string realm) : base(connectionString, realm, "GridUserStore") {} public new GridUserData Get(string userID) diff --git a/OpenSim/Data/SQLite/SQLiteHGTravelData.cs b/OpenSim/Data/SQLite/SQLiteHGTravelData.cs index db288b2486..dd347109bb 100644 --- a/OpenSim/Data/SQLite/SQLiteHGTravelData.cs +++ b/OpenSim/Data/SQLite/SQLiteHGTravelData.cs @@ -44,7 +44,7 @@ namespace OpenSim.Data.SQLite { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - public SQLiteHGTravelData(string connectionString, string realm) + public SQLiteHGTravelData(string connectionString, string realm) : base(connectionString, realm, "HGTravelStore") {} public HGTravelingData Get(UUID sessionID) diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs index 5cfc202384..eec386fcb0 100644 --- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs +++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs @@ -707,7 +707,7 @@ namespace OpenSim.Data.SQLite DataRow[] primsForRegion = prims.Select(byRegion); // m_log.Info("[SQLITE REGION DB]: Loaded " + primsForRegion.Length + " prims for region: " + regionUUID); - // First, create all groups + // First, create all groups foreach (DataRow primRow in primsForRegion) { try @@ -733,12 +733,12 @@ namespace OpenSim.Data.SQLite } SceneObjectGroup group = new SceneObjectGroup(prim); - + createdObjects.Add(group.UUID, group); retvals.Add(group); LoadItems(prim); - + } } catch (Exception e) @@ -1298,7 +1298,7 @@ namespace OpenSim.Data.SQLite createCol(prims, "VolumeDetect", typeof(Int16)); createCol(prims, "MediaURL", typeof(String)); - + createCol(prims, "AttachedPosX", typeof(Double)); createCol(prims, "AttachedPosY", typeof(Double)); createCol(prims, "AttachedPosZ", typeof(Double)); @@ -1795,7 +1795,7 @@ namespace OpenSim.Data.SQLite // m_log.DebugFormat("[SQLITE]: MediaUrl type [{0}]", row["MediaURL"].GetType()); prim.MediaUrl = (string)row["MediaURL"]; } - + prim.AttachedPos = new Vector3( Convert.ToSingle(row["AttachedPosX"]), Convert.ToSingle(row["AttachedPosY"]), @@ -1806,7 +1806,7 @@ namespace OpenSim.Data.SQLite { //m_log.DebugFormat("[SQLITE]: DynAttrs type [{0}]", row["DynAttrs"].GetType()); prim.DynAttrs = DAMap.FromXml((string)row["DynAttrs"]); - } + } else { prim.DynAttrs = new DAMap(); @@ -1818,7 +1818,7 @@ namespace OpenSim.Data.SQLite prim.Friction = Convert.ToSingle(row["Friction"]); prim.Restitution = Convert.ToSingle(row["Restitution"]); - + if (!(row["KeyframeMotion"] is DBNull)) { Byte[] data = (byte[])row["KeyframeMotion"]; @@ -2532,7 +2532,7 @@ namespace OpenSim.Data.SQLite if (!(row["Media"] is System.DBNull)) s.Media = PrimitiveBaseShape.MediaList.FromXml((string)row["Media"]); - + return s; } diff --git a/OpenSim/Data/SQLite/SQLiteUserAccountData.cs b/OpenSim/Data/SQLite/SQLiteUserAccountData.cs index 91d62cea4e..1b79185953 100644 --- a/OpenSim/Data/SQLite/SQLiteUserAccountData.cs +++ b/OpenSim/Data/SQLite/SQLiteUserAccountData.cs @@ -75,7 +75,7 @@ namespace OpenSim.Data.SQLite } else { - cmd.CommandText = String.Format("select * from {0} where (ScopeID='{1}' or ScopeID='00000000-0000-0000-0000-000000000000') and (FirstName like '{2}%' or LastName like '{3}%')", + cmd.CommandText = String.Format("select * from {0} where (ScopeID='{1}' or ScopeID='00000000-0000-0000-0000-000000000000') and (FirstName like '{2}%' or LastName like '{3}%')", m_Realm, scopeID.ToString(), words[0], words[1]); } diff --git a/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs b/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs index 2dfdba3817..13aac79049 100644 --- a/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs +++ b/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs @@ -46,43 +46,43 @@ namespace OpenSim.Data.SQLite { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private SqliteConnection m_connection; private string m_connectionString; - + private Dictionary m_FieldMap = new Dictionary(); - + protected virtual Assembly Assembly { get { return GetType().Assembly; } } - + public SQLiteUserProfilesData() { } - + public SQLiteUserProfilesData(string connectionString) { Initialise(connectionString); } - + public void Initialise(string connectionString) { if (Util.IsWindows()) Util.LoadArchSpecificWindowsDll("sqlite3.dll"); - + m_connectionString = connectionString; - + m_log.Info("[PROFILES_DATA]: Sqlite - connecting: "+m_connectionString); - + m_connection = new SqliteConnection(m_connectionString); m_connection.Open(); - + Migration m = new Migration(m_connection, Assembly, "UserProfiles"); m.Update(); } - + private string[] FieldList { get { return new List(m_FieldMap.Keys).ToArray(); } @@ -123,7 +123,7 @@ namespace OpenSim.Data.SQLite } reader.Close(); - + return data; } public bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result) @@ -162,21 +162,21 @@ namespace OpenSim.Data.SQLite query += ":ParcelName,"; query += ":Flags,"; query += ":ListingPrice ) "; - + if(string.IsNullOrEmpty(ad.ParcelName)) ad.ParcelName = "Unknown"; if(ad.ParcelId == null) ad.ParcelId = UUID.Zero; if(string.IsNullOrEmpty(ad.Description)) ad.Description = "No Description"; - + DateTime epoch = new DateTime(1970, 1, 1); DateTime now = DateTime.Now; TimeSpan epochnow = now - epoch; TimeSpan duration; DateTime expiration; TimeSpan epochexp; - + if(ad.Flags == 2) { duration = new TimeSpan(7,0,0,0); @@ -211,7 +211,7 @@ namespace OpenSim.Data.SQLite cmd.Parameters.AddWithValue(":ParcelName", ad.ParcelName.ToString()); cmd.Parameters.AddWithValue(":Flags", ad.Flags.ToString()); cmd.Parameters.AddWithValue(":ListingPrice", ad.Price.ToString ()); - + cmd.ExecuteNonQuery(); } } @@ -227,17 +227,17 @@ namespace OpenSim.Data.SQLite public bool DeleteClassifiedRecord(UUID recordId) { string query = string.Empty; - + query += "DELETE FROM classifieds WHERE "; query += "classifieduuid = :ClasifiedId"; - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) { cmd.CommandText = query; cmd.Parameters.AddWithValue(":ClassifiedId", recordId.ToString()); - + cmd.ExecuteNonQuery(); } } @@ -254,17 +254,17 @@ namespace OpenSim.Data.SQLite { IDataReader reader = null; string query = string.Empty; - + query += "SELECT * FROM classifieds WHERE "; query += "classifieduuid = :AdId"; - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) { cmd.CommandText = query; cmd.Parameters.AddWithValue(":AdId", ad.ClassifiedId.ToString()); - + using (reader = cmd.ExecuteReader()) { if(reader.Read ()) @@ -299,24 +299,24 @@ namespace OpenSim.Data.SQLite { IDataReader reader = null; string query = string.Empty; - + query += "SELECT `pickuuid`,`name` FROM userpicks WHERE "; query += "creatoruuid = :Id"; OSDArray data = new OSDArray(); - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) { cmd.CommandText = query; cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); - + using (reader = cmd.ExecuteReader()) { while (reader.Read()) { OSDMap record = new OSDMap(); - + record.Add("pickuuid",OSD.FromString((string)reader["pickuuid"])); record.Add("name",OSD.FromString((string)reader["name"])); data.Add(record); @@ -336,11 +336,11 @@ namespace OpenSim.Data.SQLite IDataReader reader = null; string query = string.Empty; UserProfilePick pick = new UserProfilePick(); - + query += "SELECT * FROM userpicks WHERE "; query += "creatoruuid = :CreatorId AND "; query += "pickuuid = :PickId"; - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) @@ -348,17 +348,17 @@ namespace OpenSim.Data.SQLite cmd.CommandText = query; cmd.Parameters.AddWithValue(":CreatorId", avatarId.ToString()); cmd.Parameters.AddWithValue(":PickId", pickId.ToString()); - + using (reader = cmd.ExecuteReader()) { - + while (reader.Read()) { string description = (string)reader["description"]; - + if (string.IsNullOrEmpty(description)) description = "No description given."; - + UUID.TryParse((string)reader["pickuuid"], out pick.PickId); UUID.TryParse((string)reader["creatoruuid"], out pick.CreatorId); UUID.TryParse((string)reader["parceluuid"], out pick.ParcelId); @@ -385,7 +385,7 @@ namespace OpenSim.Data.SQLite } public bool UpdatePicksRecord(UserProfilePick pick) - { + { string query = string.Empty; query += "INSERT OR REPLACE INTO userpicks ("; @@ -416,7 +416,7 @@ namespace OpenSim.Data.SQLite query += ":GlobalPos,"; query += ":SortOrder,"; query += ":Enabled) "; - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) @@ -456,10 +456,10 @@ namespace OpenSim.Data.SQLite public bool DeletePicksRecord(UUID pickId) { string query = string.Empty; - + query += "DELETE FROM userpicks WHERE "; query += "pickuuid = :PickId"; - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) @@ -479,15 +479,15 @@ namespace OpenSim.Data.SQLite } public bool GetAvatarNotes(ref UserProfileNotes notes) - { + { IDataReader reader = null; string query = string.Empty; - + query += "SELECT `notes` FROM usernotes WHERE "; query += "useruuid = :Id AND "; query += "targetuuid = :TargetId"; OSDArray data = new OSDArray(); - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) @@ -495,7 +495,7 @@ namespace OpenSim.Data.SQLite cmd.CommandText = query; cmd.Parameters.AddWithValue(":Id", notes.UserId.ToString()); cmd.Parameters.AddWithValue(":TargetId", notes.TargetId.ToString()); - + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { while (reader.Read()) @@ -514,10 +514,10 @@ namespace OpenSim.Data.SQLite } public bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result) - { + { string query = string.Empty; bool remove; - + if(string.IsNullOrEmpty(note.Notes)) { remove = true; @@ -533,7 +533,7 @@ namespace OpenSim.Data.SQLite query += ":TargetId,"; query += ":Notes )"; } - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) @@ -544,7 +544,7 @@ namespace OpenSim.Data.SQLite cmd.Parameters.AddWithValue(":Notes", note.Notes); cmd.Parameters.AddWithValue(":TargetId", note.TargetId.ToString ()); cmd.Parameters.AddWithValue(":UserId", note.UserId.ToString()); - + cmd.ExecuteNonQuery(); } } @@ -561,7 +561,7 @@ namespace OpenSim.Data.SQLite { IDataReader reader = null; string query = string.Empty; - + query += "SELECT * FROM userprofile WHERE "; query += "useruuid = :Id"; @@ -569,7 +569,7 @@ namespace OpenSim.Data.SQLite { cmd.CommandText = query; cmd.Parameters.AddWithValue(":Id", props.UserId.ToString()); - + try { @@ -611,7 +611,7 @@ namespace OpenSim.Data.SQLite props.Language = string.Empty; props.PublishProfile = false; props.PublishMature = false; - + query = "INSERT INTO userprofile ("; query += "useruuid, "; query += "profilePartner, "; @@ -659,7 +659,7 @@ namespace OpenSim.Data.SQLite put.Parameters.AddWithValue(":profileAboutText", props.AboutText); put.Parameters.AddWithValue(":profileFirstImage", props.FirstLifeImageId.ToString()); put.Parameters.AddWithValue(":profileFirstText", props.FirstLifeText); - + put.ExecuteNonQuery(); } } @@ -668,9 +668,9 @@ namespace OpenSim.Data.SQLite } public bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result) - { + { string query = string.Empty; - + query += "UPDATE userprofile SET "; query += "profileURL=:profileURL, "; query += "profileImage=:image, "; @@ -678,7 +678,7 @@ namespace OpenSim.Data.SQLite query += "profileFirstImage=:firstlifeimage,"; query += "profileFirstText=:firstlifetext "; query += "WHERE useruuid=:uuid"; - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) @@ -690,7 +690,7 @@ namespace OpenSim.Data.SQLite cmd.Parameters.AddWithValue(":firstlifeimage", props.FirstLifeImageId.ToString()); cmd.Parameters.AddWithValue(":firstlifetext", props.FirstLifeText); cmd.Parameters.AddWithValue(":uuid", props.UserId.ToString()); - + cmd.ExecuteNonQuery(); } } @@ -698,16 +698,16 @@ namespace OpenSim.Data.SQLite { m_log.ErrorFormat("[PROFILES_DATA]" + ": AgentPropertiesUpdate exception {0}", e.Message); - + return false; } return true; } public bool UpdateAvatarInterests(UserProfileProperties up, ref string result) - { + { string query = string.Empty; - + query += "UPDATE userprofile SET "; query += "profileWantToMask=:WantMask, "; query += "profileWantToText=:WantText,"; @@ -715,7 +715,7 @@ namespace OpenSim.Data.SQLite query += "profileSkillsText=:SkillsText, "; query += "profileLanguages=:Languages "; query += "WHERE useruuid=:uuid"; - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) @@ -727,7 +727,7 @@ namespace OpenSim.Data.SQLite cmd.Parameters.AddWithValue(":SkillsText", up.SkillsText); cmd.Parameters.AddWithValue(":Languages", up.Language); cmd.Parameters.AddWithValue(":uuid", up.UserId.ToString()); - + cmd.ExecuteNonQuery(); } } @@ -741,17 +741,17 @@ namespace OpenSim.Data.SQLite return true; } - + public bool UpdateUserPreferences(ref UserPreferences pref, ref string result) - { + { string query = string.Empty; - + query += "UPDATE usersettings SET "; query += "imviaemail=:ImViaEmail, "; query += "visible=:Visible, "; query += "email=:EMail "; query += "WHERE useruuid=:uuid"; - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) @@ -761,7 +761,7 @@ namespace OpenSim.Data.SQLite cmd.Parameters.AddWithValue(":Visible", pref.Visible); cmd.Parameters.AddWithValue(":EMail", pref.EMail); cmd.Parameters.AddWithValue(":uuid", pref.UserId.ToString()); - + cmd.ExecuteNonQuery(); } } @@ -779,20 +779,20 @@ namespace OpenSim.Data.SQLite { IDataReader reader = null; string query = string.Empty; - + query += "SELECT imviaemail,visible,email FROM "; query += "usersettings WHERE "; query += "useruuid = :Id"; - + OSDArray data = new OSDArray(); - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) { cmd.CommandText = query; cmd.Parameters.AddWithValue("?Id", pref.UserId.ToString()); - + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { if(reader.Read()) @@ -805,13 +805,13 @@ namespace OpenSim.Data.SQLite { query = "INSERT INTO usersettings VALUES "; query += "(:Id,'false','false', :Email)"; - + using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand()) { put.Parameters.AddWithValue(":Id", pref.UserId.ToString()); put.Parameters.AddWithValue(":Email", pref.EMail); put.ExecuteNonQuery(); - + } } } @@ -831,11 +831,11 @@ namespace OpenSim.Data.SQLite { IDataReader reader = null; string query = string.Empty; - + query += "SELECT * FROM `userdata` WHERE "; query += "UserId = :Id AND "; query += "TagId = :TagId"; - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) @@ -843,7 +843,7 @@ namespace OpenSim.Data.SQLite cmd.CommandText = query; cmd.Parameters.AddWithValue(":Id", props.UserId.ToString()); cmd.Parameters.AddWithValue (":TagId", props.TagId.ToString()); - + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { if(reader.Read()) @@ -858,7 +858,7 @@ namespace OpenSim.Data.SQLite query += ":TagId,"; query += ":DataKey,"; query += ":DataVal) "; - + using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand()) { put.Parameters.AddWithValue(":Id", props.UserId.ToString()); @@ -882,16 +882,16 @@ namespace OpenSim.Data.SQLite return true; } public bool SetUserAppData(UserAppData props, ref string result) - { + { string query = string.Empty; - + query += "UPDATE userdata SET "; query += "TagId = :TagId, "; query += "DataKey = :DataKey, "; query += "DataVal = :DataVal WHERE "; query += "UserId = :UserId AND "; query += "TagId = :TagId"; - + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) @@ -918,17 +918,17 @@ namespace OpenSim.Data.SQLite IDataReader reader = null; OSDArray data = new OSDArray(); string query = "SELECT `snapshotuuid` FROM {0} WHERE `creatoruuid` = :Id"; - + // Get classified image assets - - + + try { using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) { cmd.CommandText = query; cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); - + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { while(reader.Read()) @@ -942,7 +942,7 @@ namespace OpenSim.Data.SQLite { cmd.CommandText = query; cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); - + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { if(reader.Read()) @@ -951,14 +951,14 @@ namespace OpenSim.Data.SQLite } } } - + query = "SELECT `profileImage`, `profileFirstImage` FROM `userprofile` WHERE `useruuid` = :Id"; - + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) { cmd.CommandText = query; cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); - + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { if(reader.Read()) diff --git a/OpenSim/Data/SQLite/SQLiteUtils.cs b/OpenSim/Data/SQLite/SQLiteUtils.cs index ca5861fefd..1218ebbb94 100644 --- a/OpenSim/Data/SQLite/SQLiteUtils.cs +++ b/OpenSim/Data/SQLite/SQLiteUtils.cs @@ -49,7 +49,7 @@ namespace OpenSim.Data.SQLite **********************************************************************/ /// - /// + /// /// /// /// @@ -147,7 +147,7 @@ namespace OpenSim.Data.SQLite } /// - /// + /// /// /// Data Table /// @@ -191,7 +191,7 @@ namespace OpenSim.Data.SQLite /// lines for defining SqliteParameters to 2 parameters: /// column name and database type. /// - /// + /// /// /// It assumes certain conventions like :param as the param /// name to replace in parametrized queries, and that source diff --git a/OpenSim/Data/SQLite/SQLiteXInventoryData.cs b/OpenSim/Data/SQLite/SQLiteXInventoryData.cs index 2a0a8f6cc9..7f44a651e9 100644 --- a/OpenSim/Data/SQLite/SQLiteXInventoryData.cs +++ b/OpenSim/Data/SQLite/SQLiteXInventoryData.cs @@ -107,7 +107,7 @@ namespace OpenSim.Data.SQLite public bool DeleteItems(string[] fields, string[] vals) { return m_Items.Delete(fields, vals); - } + } public bool MoveItem(string id, string newParent) { @@ -302,7 +302,7 @@ namespace OpenSim.Data.SQLite { // m_log.DebugFormat("[MYSQL ITEM HANDLER]: Incrementing version on folder {0}", folderID); // Util.PrintCallStack(); - + using (SqliteCommand cmd = new SqliteCommand()) { cmd.CommandText = "update inventoryfolders set version=version+1 where folderID = ?folderID"; diff --git a/OpenSim/Data/Tests/AssetTests.cs b/OpenSim/Data/Tests/AssetTests.cs index 5982a091df..70880cf83a 100644 --- a/OpenSim/Data/Tests/AssetTests.cs +++ b/OpenSim/Data/Tests/AssetTests.cs @@ -110,7 +110,7 @@ namespace OpenSim.Data.Tests public void T010_StoreReadVerifyAssets() { TestHelpers.InMethod(); - + AssetBase a1 = new AssetBase(uuid1, "asset one", (sbyte)AssetType.Texture, critter1.ToString()); AssetBase a2 = new AssetBase(uuid2, "asset two", (sbyte)AssetType.Texture, critter2.ToString()); AssetBase a3 = new AssetBase(uuid3, "asset three", (sbyte)AssetType.Texture, critter3.ToString()); @@ -128,7 +128,7 @@ namespace OpenSim.Data.Tests a1.UploadAttempts = 0; a2.UploadAttempts = 0; a3.UploadAttempts = 0; - + AssetBase a1a = m_db.GetAsset(uuid1); a1a.UploadAttempts = 0; Assert.That(a1a, Constraints.PropertyCompareConstraint(a1)); @@ -190,7 +190,7 @@ namespace OpenSim.Data.Tests public void T020_CheckForWeirdCreatorID() { TestHelpers.InMethod(); - + // It is expected that eventually the CreatorID might be an arbitrary string (an URI) // rather than a valid UUID (?). This test is to make sure that the database layer does not // attempt to convert CreatorID to GUID, but just passes it both ways as a string. diff --git a/OpenSim/Data/Tests/BasicDataServiceTest.cs b/OpenSim/Data/Tests/BasicDataServiceTest.cs index acfebd0206..79691e48ac 100644 --- a/OpenSim/Data/Tests/BasicDataServiceTest.cs +++ b/OpenSim/Data/Tests/BasicDataServiceTest.cs @@ -41,11 +41,11 @@ using System.Reflection; namespace OpenSim.Data.Tests { - /// This is a base class for testing any Data service for any DBMS. + /// This is a base class for testing any Data service for any DBMS. /// Requires NUnit 2.5 or better (to support the generics). /// /// - /// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with + /// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with /// AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true. /// and similar on EstateTests, InventoryTests and RegionTests. /// Runs fine with mono 2.10.8.1, so easiest thing is to wait until min Mono version uplifts. @@ -60,7 +60,7 @@ namespace OpenSim.Data.Tests private TService m_service; private string m_file; - // TODO: Is this in the right place here? + // TODO: Is this in the right place here? // Later: apparently it's not, but does it matter here? // protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -68,7 +68,7 @@ namespace OpenSim.Data.Tests public BasicDataServiceTest() : this("") - { + { } public BasicDataServiceTest(string conn) @@ -226,7 +226,7 @@ namespace OpenSim.Data.Tests } } - /// Clear tables listed as parameters (without dropping them). + /// Clear tables listed as parameters (without dropping them). /// /// protected virtual void ResetMigrations(params string[] stores) @@ -251,7 +251,7 @@ namespace OpenSim.Data.Tests } } - /// Clear tables listed as parameters (without dropping them). + /// Clear tables listed as parameters (without dropping them). /// /// protected virtual void ClearTables(params string[] tables) diff --git a/OpenSim/Data/Tests/DefaultTestConns.cs b/OpenSim/Data/Tests/DefaultTestConns.cs index 7c47bddd21..5ad238b660 100644 --- a/OpenSim/Data/Tests/DefaultTestConns.cs +++ b/OpenSim/Data/Tests/DefaultTestConns.cs @@ -39,16 +39,16 @@ namespace OpenSim.Data.Tests /// a connection string for testing one of the supported databases. /// The connections must be in the section [TestConnections] with names matching the connection class /// name for the specific database, e.g.: - /// + /// /// [TestConnections] /// MySqlConnection="..." /// SqlConnection="..." /// SqliteConnection="..." - /// + /// /// Note that the conn string may also be set explicitly in the [TestCase()] attribute of test classes /// based on BasicDataServiceTest.cs. /// - + static class DefaultTestConns { private static Dictionary conns = new Dictionary(); @@ -63,8 +63,8 @@ namespace OpenSim.Data.Tests Assembly asm = Assembly.GetExecutingAssembly(); string sType = connType.Name; - // Note: when running from NUnit, the DLL is located in some temp dir, so how do we get - // to the INI file? Ok, so put it into the resources! + // Note: when running from NUnit, the DLL is located in some temp dir, so how do we get + // to the INI file? Ok, so put it into the resources! // string iniName = Path.Combine(Path.GetDirectoryName(asm.Location), "TestDataConnections.ini"); string[] allres = asm.GetManifestResourceNames(); diff --git a/OpenSim/Data/Tests/EstateTests.cs b/OpenSim/Data/Tests/EstateTests.cs index e2b2d12aaa..cf3f2b4602 100644 --- a/OpenSim/Data/Tests/EstateTests.cs +++ b/OpenSim/Data/Tests/EstateTests.cs @@ -100,7 +100,7 @@ namespace OpenSim.Data.Tests public void T010_EstateSettingsSimpleStorage_MinimumParameterSet() { TestHelpers.InMethod(); - + EstateSettingsSimpleStorage( REGION_ID, DataTestUtil.STRING_MIN, @@ -133,7 +133,7 @@ namespace OpenSim.Data.Tests public void T011_EstateSettingsSimpleStorage_MaximumParameterSet() { TestHelpers.InMethod(); - + EstateSettingsSimpleStorage( REGION_ID, DataTestUtil.STRING_MAX(64), @@ -166,7 +166,7 @@ namespace OpenSim.Data.Tests public void T012_EstateSettingsSimpleStorage_AccurateParameterSet() { TestHelpers.InMethod(); - + EstateSettingsSimpleStorage( REGION_ID, DataTestUtil.STRING_MAX(1), @@ -199,7 +199,7 @@ namespace OpenSim.Data.Tests public void T012_EstateSettingsRandomStorage() { TestHelpers.InMethod(); - + // Letting estate store generate rows to database for us EstateSettings originalSettings = db.LoadEstateSettings(REGION_ID, true); new PropertyScrambler() @@ -220,7 +220,7 @@ namespace OpenSim.Data.Tests public void T020_EstateSettingsManagerList() { TestHelpers.InMethod(); - + // Letting estate store generate rows to database for us EstateSettings originalSettings = db.LoadEstateSettings(REGION_ID, true); @@ -241,7 +241,7 @@ namespace OpenSim.Data.Tests public void T021_EstateSettingsUserList() { TestHelpers.InMethod(); - + // Letting estate store generate rows to database for us EstateSettings originalSettings = db.LoadEstateSettings(REGION_ID, true); @@ -262,7 +262,7 @@ namespace OpenSim.Data.Tests public void T022_EstateSettingsGroupList() { TestHelpers.InMethod(); - + // Letting estate store generate rows to database for us EstateSettings originalSettings = db.LoadEstateSettings(REGION_ID, true); @@ -283,7 +283,7 @@ namespace OpenSim.Data.Tests public void T022_EstateSettingsBanList() { TestHelpers.InMethod(); - + // Letting estate store generate rows to database for us EstateSettings originalSettings = db.LoadEstateSettings(REGION_ID, true); @@ -310,7 +310,7 @@ namespace OpenSim.Data.Tests #endregion - #region Parametrizable Test Implementations + #region Parametrizable Test Implementations private void EstateSettingsSimpleStorage( UUID regionId, diff --git a/OpenSim/Data/Tests/InventoryTests.cs b/OpenSim/Data/Tests/InventoryTests.cs index e4ec5c18fe..da6e7d46fd 100644 --- a/OpenSim/Data/Tests/InventoryTests.cs +++ b/OpenSim/Data/Tests/InventoryTests.cs @@ -46,7 +46,7 @@ namespace OpenSim.Data.Tests { [TestFixture(Description = "Inventory store tests (MySQL)")] public class MySqlInventoryTests : InventoryTests - { + { } public class InventoryTests : BasicDataServiceTest @@ -102,7 +102,7 @@ namespace OpenSim.Data.Tests public void T001_LoadEmpty() { TestHelpers.InMethod(); - + Assert.That(db.getInventoryFolder(zero), Is.Null); Assert.That(db.getInventoryFolder(folder1), Is.Null); Assert.That(db.getInventoryFolder(folder2), Is.Null); @@ -122,7 +122,7 @@ namespace OpenSim.Data.Tests public void T010_FolderNonParent() { TestHelpers.InMethod(); - + InventoryFolderBase f1 = NewFolder(folder2, folder1, owner1, name2); // the folder will go in db.addInventoryFolder(f1); @@ -134,7 +134,7 @@ namespace OpenSim.Data.Tests public void T011_FolderCreate() { TestHelpers.InMethod(); - + InventoryFolderBase f1 = NewFolder(folder1, zero, owner1, name1); // TODO: this is probably wrong behavior, but is what we have // db.updateInventoryFolder(f1); @@ -159,7 +159,7 @@ namespace OpenSim.Data.Tests public void T012_FolderList() { TestHelpers.InMethod(); - + InventoryFolderBase f2 = NewFolder(folder3, folder1, owner1, name3); db.addInventoryFolder(f2); @@ -175,7 +175,7 @@ namespace OpenSim.Data.Tests public void T013_FolderHierarchy() { TestHelpers.InMethod(); - + int n = db.getFolderHierarchy(zero).Count; // (for dbg - easier to see what's returned) Assert.That(n, Is.EqualTo(0), "Assert.That(db.getFolderHierarchy(zero).Count, Is.EqualTo(0))"); n = db.getFolderHierarchy(folder1).Count; @@ -190,7 +190,7 @@ namespace OpenSim.Data.Tests public void T014_MoveFolder() { TestHelpers.InMethod(); - + InventoryFolderBase f2 = db.getInventoryFolder(folder2); f2.ParentID = folder3; db.moveInventoryFolder(f2); @@ -206,7 +206,7 @@ namespace OpenSim.Data.Tests public void T015_FolderHierarchy() { TestHelpers.InMethod(); - + Assert.That(db.getFolderHierarchy(zero).Count, Is.EqualTo(0), "Assert.That(db.getFolderHierarchy(zero).Count, Is.EqualTo(0))"); Assert.That(db.getFolderHierarchy(folder1).Count, Is.EqualTo(2), "Assert.That(db.getFolderHierarchy(folder1).Count, Is.EqualTo(2))"); Assert.That(db.getFolderHierarchy(folder2).Count, Is.EqualTo(0), "Assert.That(db.getFolderHierarchy(folder2).Count, Is.EqualTo(0))"); @@ -219,7 +219,7 @@ namespace OpenSim.Data.Tests public void T100_NoItems() { TestHelpers.InMethod(); - + Assert.That(db.getInventoryInFolder(zero).Count, Is.EqualTo(0), "Assert.That(db.getInventoryInFolder(zero).Count, Is.EqualTo(0))"); Assert.That(db.getInventoryInFolder(folder1).Count, Is.EqualTo(0), "Assert.That(db.getInventoryInFolder(folder1).Count, Is.EqualTo(0))"); Assert.That(db.getInventoryInFolder(folder2).Count, Is.EqualTo(0), "Assert.That(db.getInventoryInFolder(folder2).Count, Is.EqualTo(0))"); @@ -233,7 +233,7 @@ namespace OpenSim.Data.Tests public void T101_CreatItems() { TestHelpers.InMethod(); - + db.addInventoryItem(NewItem(item1, folder3, owner1, iname1, asset1)); db.addInventoryItem(NewItem(item2, folder3, owner1, iname2, asset2)); db.addInventoryItem(NewItem(item3, folder3, owner1, iname3, asset3)); @@ -244,7 +244,7 @@ namespace OpenSim.Data.Tests public void T102_CompareItems() { TestHelpers.InMethod(); - + InventoryItemBase i1 = db.getInventoryItem(item1); InventoryItemBase i2 = db.getInventoryItem(item2); InventoryItemBase i3 = db.getInventoryItem(item3); @@ -263,7 +263,7 @@ namespace OpenSim.Data.Tests public void T103_UpdateItem() { TestHelpers.InMethod(); - + // TODO: probably shouldn't have the ability to have an // owner of an item in a folder not owned by the user @@ -283,7 +283,7 @@ namespace OpenSim.Data.Tests public void T104_RandomUpdateItem() { TestHelpers.InMethod(); - + PropertyScrambler folderScrambler = new PropertyScrambler() .DontScramble(x => x.Owner) @@ -342,7 +342,7 @@ namespace OpenSim.Data.Tests public void T999_StillNull() { TestHelpers.InMethod(); - + // After all tests are run, these should still return no results Assert.That(db.getInventoryFolder(zero), Is.Null); Assert.That(db.getInventoryItem(zero), Is.Null); diff --git a/OpenSim/Data/Tests/PropertyScrambler.cs b/OpenSim/Data/Tests/PropertyScrambler.cs index e0f5862b93..0d291df0b3 100644 --- a/OpenSim/Data/Tests/PropertyScrambler.cs +++ b/OpenSim/Data/Tests/PropertyScrambler.cs @@ -42,7 +42,7 @@ namespace OpenSim.Data.Tests public class PropertyScrambler { readonly System.Collections.Generic.List membersToNotScramble = new List(); - + private void AddExpressionToNotScrableList(Expression expression) { UnaryExpression unaryExpression = expression as UnaryExpression; diff --git a/OpenSim/Data/Tests/RegionTests.cs b/OpenSim/Data/Tests/RegionTests.cs index e1503d0378..4f81594993 100644 --- a/OpenSim/Data/Tests/RegionTests.cs +++ b/OpenSim/Data/Tests/RegionTests.cs @@ -83,7 +83,7 @@ namespace OpenSim.Data.Tests public UUID item3 = UUID.Random(); public static Random random = new Random(); - + public string itemname1 = "item1"; public uint localID = 1; @@ -111,10 +111,10 @@ namespace OpenSim.Data.Tests private void ClearDB() { - string[] reg_tables = new string[] { - "prims", "primshapes", "primitems", "terrain", "land", "landaccesslist", "regionban", "regionsettings" + string[] reg_tables = new string[] { + "prims", "primshapes", "primitems", "terrain", "land", "landaccesslist", "regionban", "regionsettings" }; - + if (m_rebuildDB) { DropTables(reg_tables); @@ -145,7 +145,7 @@ namespace OpenSim.Data.Tests public void T001_LoadEmpty() { TestHelpers.InMethod(); - + List objs = db.LoadObjects(region1); List objs3 = db.LoadObjects(region3); List land = db.LoadLandObjects(region1); @@ -154,21 +154,21 @@ namespace OpenSim.Data.Tests Assert.That(objs3.Count, Is.EqualTo(0), "Assert.That(objs3.Count, Is.EqualTo(0))"); Assert.That(land.Count, Is.EqualTo(0), "Assert.That(land.Count, Is.EqualTo(0))"); } - + // SOG round trips // * store objects, make sure they save - // * update + // * update [Test] public void T010_StoreSimpleObject() { TestHelpers.InMethod(); - + SceneObjectGroup sog = NewSOG("object1", prim1, region1); SceneObjectGroup sog2 = NewSOG("object2", prim2, region1); // in case the objects don't store - try + try { db.StoreObject(sog, region1); } @@ -177,8 +177,8 @@ namespace OpenSim.Data.Tests m_log.Error(e.ToString()); Assert.Fail(); } - - try + + try { db.StoreObject(sog2, region1); } @@ -190,15 +190,15 @@ namespace OpenSim.Data.Tests // This tests the ADO.NET driver List objs = db.LoadObjects(region1); - + Assert.That(objs.Count, Is.EqualTo(2), "Assert.That(objs.Count, Is.EqualTo(2))"); } - + [Test] public void T011_ObjectNames() { TestHelpers.InMethod(); - + List objs = db.LoadObjects(region1); foreach (SceneObjectGroup sog in objs) { @@ -207,12 +207,12 @@ namespace OpenSim.Data.Tests Assert.That(p.Name, Is.EqualTo(p.Description), "Assert.That(p.Name, Is.EqualTo(p.Description))"); } } - + [Test] public void T012_SceneParts() { TestHelpers.InMethod(); - + UUID tmp0 = UUID.Random(); UUID tmp1 = UUID.Random(); UUID tmp2 = UUID.Random(); @@ -225,10 +225,10 @@ namespace OpenSim.Data.Tests sog.AddPart(p1); sog.AddPart(p2); sog.AddPart(p3); - + SceneObjectPart[] parts = sog.Parts; Assert.That(parts.Length,Is.EqualTo(4), "Assert.That(parts.Length,Is.EqualTo(4))"); - + db.StoreObject(sog, newregion); List sogs = db.LoadObjects(newregion); Assert.That(sogs.Count,Is.EqualTo(1), "Assert.That(sogs.Count,Is.EqualTo(1))"); @@ -236,18 +236,18 @@ namespace OpenSim.Data.Tests SceneObjectPart[] newparts = newsog.Parts; Assert.That(newparts.Length,Is.EqualTo(4), "Assert.That(newparts.Length,Is.EqualTo(4))"); - + Assert.That(newsog.ContainsPart(tmp0), "Assert.That(newsog.ContainsPart(tmp0))"); Assert.That(newsog.ContainsPart(tmp1), "Assert.That(newsog.ContainsPart(tmp1))"); Assert.That(newsog.ContainsPart(tmp2), "Assert.That(newsog.ContainsPart(tmp2))"); Assert.That(newsog.ContainsPart(tmp3), "Assert.That(newsog.ContainsPart(tmp3))"); } - + [Test] public void T013_DatabasePersistency() { TestHelpers.InMethod(); - + // Sets all ScenePart parameters, stores and retrieves them, then check for consistency with initial data // The commented Asserts are the ones that are unchangeable (when storing on the database, their "Set" values are ignored // The ObjectFlags is an exception, if it is entered incorrectly, the object IS REJECTED on the database silently. @@ -298,7 +298,7 @@ namespace OpenSim.Data.Tests SceneObjectPart sop = new SceneObjectPart(); SceneObjectGroup sog = new SceneObjectGroup(sop); - + sop.RegionHandle = regionh; sop.UUID = uuid; sop.LocalId = localid; @@ -360,10 +360,10 @@ namespace OpenSim.Data.Tests Assert.That(linknum,Is.EqualTo(sop.LinkNum), "Assert.That(linknum,Is.EqualTo(sop.LinkNum))"); Assert.That(clickaction,Is.EqualTo(sop.ClickAction), "Assert.That(clickaction,Is.EqualTo(sop.ClickAction))"); Assert.That(scale,Is.EqualTo(sop.Scale), "Assert.That(scale,Is.EqualTo(sop.Scale))"); - + // This is necessary or object will not be inserted in DB sop.Flags = PrimFlags.None; - + // Inserts group in DB db.StoreObject(sog,region3); List sogs = db.LoadObjects(region3); @@ -372,7 +372,7 @@ namespace OpenSim.Data.Tests db.StoreObject(sog,region3); sogs = db.LoadObjects(region3); Assert.That(sogs.Count, Is.EqualTo(1), "Assert.That(sogs.Count, Is.EqualTo(1))"); - + // Tests if the parameters were inserted correctly SceneObjectPart p = sogs[0].RootPart; @@ -414,12 +414,12 @@ namespace OpenSim.Data.Tests Assert.That(pbshap.ProfileEnd, Is.EqualTo(p.Shape.ProfileEnd), "Assert.That(pbshap.ProfileEnd, Is.EqualTo(p.Shape.ProfileEnd))"); Assert.That(pbshap.ProfileHollow, Is.EqualTo(p.Shape.ProfileHollow), "Assert.That(pbshap.ProfileHollow, Is.EqualTo(p.Shape.ProfileHollow))"); } - + [Test] public void T014_UpdateObject() { TestHelpers.InMethod(); - + string text1 = "object1 text"; SceneObjectGroup sog = FindSOG("object1", region1); sog.RootPart.Text = text1; @@ -459,7 +459,7 @@ namespace OpenSim.Data.Tests PrimitiveBaseShape pbshap = new PrimitiveBaseShape(); pbshap = PrimitiveBaseShape.Default; Vector3 scale = new Vector3(random.Next(),random.Next(),random.Next()); - + // Updates the region with new values SceneObjectGroup sog2 = FindSOG("Adam West", region3); Assert.That(sog2,Is.Not.Null); @@ -488,11 +488,11 @@ namespace OpenSim.Data.Tests sog2.RootPart.LinkNum = linknum; sog2.RootPart.ClickAction = clickaction; sog2.RootPart.Scale = scale; - + db.StoreObject(sog2, region3); List sogs = db.LoadObjects(region3); Assert.That(sogs.Count, Is.EqualTo(1), "Assert.That(sogs.Count, Is.EqualTo(1))"); - + SceneObjectGroup retsog = FindSOG("West Adam", region3); Assert.That(retsog,Is.Not.Null); SceneObjectPart p = retsog.RootPart; @@ -519,7 +519,7 @@ namespace OpenSim.Data.Tests Assert.That(clickaction,Is.EqualTo(p.ClickAction), "Assert.That(clickaction,Is.EqualTo(p.ClickAction))"); Assert.That(scale,Is.EqualTo(p.Scale), "Assert.That(scale,Is.EqualTo(p.Scale))"); } - + /// /// Test storage and retrieval of a scene object with a large number of parts. /// @@ -527,12 +527,12 @@ namespace OpenSim.Data.Tests public void T015_LargeSceneObjects() { TestHelpers.InMethod(); - + UUID id = UUID.Random(); Dictionary mydic = new Dictionary(); SceneObjectGroup sog = NewSOG("Test SOG", id, region4); mydic.Add(sog.RootPart.UUID,sog.RootPart); - for (int i = 0; i < 30; i++) + for (int i = 0; i < 30; i++) { UUID tmp = UUID.Random(); SceneObjectPart sop = NewSOP(("Test SOP " + i.ToString()),tmp); @@ -542,20 +542,20 @@ namespace OpenSim.Data.Tests Vector3 velocity = new Vector3(random.Next(),random.Next(),random.Next()); Vector3 angvelo = new Vector3(random.Next(),random.Next(),random.Next()); Vector3 accel = new Vector3(random.Next(),random.Next(),random.Next()); - + sop.GroupPosition = groupos; sop.RotationOffset = rotoff; sop.OffsetPosition = offset; sop.Velocity = velocity; sop.AngularVelocity = angvelo; sop.Acceleration = accel; - + mydic.Add(tmp,sop); - sog.AddPart(sop); + sog.AddPart(sop); } - + db.StoreObject(sog, region4); - + SceneObjectGroup retsog = FindSOG("Test SOG", region4); SceneObjectPart[] parts = retsog.Parts; for (int i = 0; i < 30; i++) @@ -574,7 +574,7 @@ namespace OpenSim.Data.Tests public void T016_RandomSogWithSceneParts() { TestHelpers.InMethod(); - + PropertyScrambler scrambler = new PropertyScrambler() .DontScramble(x => x.UUID); @@ -634,22 +634,22 @@ namespace OpenSim.Data.Tests SceneObjectGroup sog = FindSOG(name, region1); if (sog == null) { - sog = NewSOG(name, prim1, region1); + sog = NewSOG(name, prim1, region1); db.StoreObject(sog, region1); } return sog; } - + // NOTE: it is a bad practice to rely on some of the previous tests having been run before. // If the tests are run manually, one at a time, each starts with full class init (DB cleared). // Even when all tests are run, NUnit 2.5+ no longer guarantee a specific test order. // We shouldn't expect to find anything in the DB if we haven't put it there *in the same test*! - + [Test] public void T020_PrimInventoryEmpty() { TestHelpers.InMethod(); - + SceneObjectGroup sog = GetMySOG("object1"); TaskInventoryItem t = sog.GetInventoryItem(sog.RootPart.LocalId, item1); Assert.That(t, Is.Null); @@ -673,14 +673,14 @@ namespace OpenSim.Data.Tests public void T021_PrimInventoryBasic() { TestHelpers.InMethod(); - + SceneObjectGroup sog = GetMySOG("object1"); InventoryItemBase i = NewItem(item1, zero, zero, itemname1, zero); Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, i, zero), Is.True); TaskInventoryItem t = sog.GetInventoryItem(sog.RootPart.LocalId, item1); Assert.That(t.Name, Is.EqualTo(itemname1), "Assert.That(t.Name, Is.EqualTo(itemname1))"); - + StoreInventory(sog); SceneObjectGroup sog1 = FindSOG("object1", region1); @@ -708,12 +708,12 @@ namespace OpenSim.Data.Tests t = sog.GetInventoryItem(sog.RootPart.LocalId, item1); Assert.That(t, Is.Null); } - + [Test] public void T025_PrimInventoryPersistency() { TestHelpers.InMethod(); - + InventoryItemBase i = new InventoryItemBase(); UUID id = UUID.Random(); i.ID = id; @@ -752,11 +752,11 @@ namespace OpenSim.Data.Tests i.Flags = flags; int creationd = random.Next(); i.CreationDate = creationd; - + SceneObjectGroup sog = GetMySOG("object1"); Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, i, zero), Is.True); TaskInventoryItem t = sog.GetInventoryItem(sog.RootPart.LocalId, id); - + Assert.That(t.Name, Is.EqualTo(name), "Assert.That(t.Name, Is.EqualTo(name))"); Assert.That(t.AssetID,Is.EqualTo(assetid), "Assert.That(t.AssetID,Is.EqualTo(assetid))"); Assert.That(t.BasePermissions,Is.EqualTo(baseperm), "Assert.That(t.BasePermissions,Is.EqualTo(baseperm))"); @@ -780,13 +780,13 @@ namespace OpenSim.Data.Tests Assert.That(t.ParentID,Is.EqualTo(sog.RootPart.FolderID), "Assert.That(t.ParentID,Is.EqualTo(sog.RootPart.FolderID))"); Assert.That(t.ParentPartID,Is.EqualTo(sog.RootPart.UUID), "Assert.That(t.ParentPartID,Is.EqualTo(sog.RootPart.UUID))"); } - + [Test] [ExpectedException(typeof(ArgumentException))] public void T026_PrimInventoryMany() { TestHelpers.InMethod(); - + UUID i1,i2,i3,i4; i1 = UUID.Random(); i2 = UUID.Random(); @@ -796,14 +796,14 @@ namespace OpenSim.Data.Tests InventoryItemBase ib2 = NewItem(i2, zero, zero, RandomName(), zero); InventoryItemBase ib3 = NewItem(i3, zero, zero, RandomName(), zero); InventoryItemBase ib4 = NewItem(i4, zero, zero, RandomName(), zero); - + SceneObjectGroup sog = FindSOG("object1", region1); Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, ib1, zero), Is.True); Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, ib2, zero), Is.True); Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, ib3, zero), Is.True); Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, ib4, zero), Is.True); - + TaskInventoryItem t1 = sog.GetInventoryItem(sog.RootPart.LocalId, i1); Assert.That(t1.Name, Is.EqualTo(ib1.Name), "Assert.That(t1.Name, Is.EqualTo(ib1.Name))"); TaskInventoryItem t2 = sog.GetInventoryItem(sog.RootPart.LocalId, i2); @@ -818,7 +818,7 @@ namespace OpenSim.Data.Tests public void T052_RemoveObject() { TestHelpers.InMethod(); - + db.RemoveObject(prim1, region1); SceneObjectGroup sog = FindSOG("object1", region1); Assert.That(sog, Is.Null); @@ -828,7 +828,7 @@ namespace OpenSim.Data.Tests public void T100_DefaultRegionInfo() { TestHelpers.InMethod(); - + RegionSettings r1 = db.LoadRegionSettings(region1); Assert.That(r1.RegionUUID, Is.EqualTo(region1), "Assert.That(r1.RegionUUID, Is.EqualTo(region1))"); @@ -840,7 +840,7 @@ namespace OpenSim.Data.Tests public void T101_UpdateRegionInfo() { TestHelpers.InMethod(); - + int agentlimit = random.Next(); double objectbonus = random.Next(); int maturity = random.Next(); @@ -900,9 +900,9 @@ namespace OpenSim.Data.Tests r1.FixedSun = true; r1.SunPosition = sunpos; r1.Covenant = cov; - + db.StoreRegionSettings(r1); - + RegionSettings r1a = db.LoadRegionSettings(region1); Assert.That(r1a.RegionUUID, Is.EqualTo(region1), "Assert.That(r1a.RegionUUID, Is.EqualTo(region1))"); Assert.That(r1a.BlockTerraform,Is.True); @@ -939,14 +939,14 @@ namespace OpenSim.Data.Tests //Assert.That(r1a.TerrainImageID,Is.EqualTo(terimgid), "Assert.That(r1a.TerrainImageID,Is.EqualTo(terimgid))"); Assert.That(r1a.FixedSun,Is.True); Assert.That(r1a.SunPosition, Is.EqualTo(sunpos), "Assert.That(r1a.SunPosition, Is.EqualTo(sunpos))"); - Assert.That(r1a.Covenant, Is.EqualTo(cov), "Assert.That(r1a.Covenant, Is.EqualTo(cov))"); + Assert.That(r1a.Covenant, Is.EqualTo(cov), "Assert.That(r1a.Covenant, Is.EqualTo(cov))"); } [Test] public void T300_NoTerrain() { TestHelpers.InMethod(); - + Assert.That(db.LoadTerrain(zero), Is.Null); Assert.That(db.LoadTerrain(region1), Is.Null); Assert.That(db.LoadTerrain(region2), Is.Null); @@ -957,13 +957,13 @@ namespace OpenSim.Data.Tests public void T301_CreateTerrain() { TestHelpers.InMethod(); - + double[,] t1 = GenTerrain(height1); db.StoreTerrain(t1, region1); - + // store terrain is async Thread.Sleep(1000); - + Assert.That(db.LoadTerrain(zero), Is.Null); Assert.That(db.LoadTerrain(region1), Is.Not.Null); Assert.That(db.LoadTerrain(region2), Is.Null); @@ -974,7 +974,7 @@ namespace OpenSim.Data.Tests public void T302_FetchTerrain() { TestHelpers.InMethod(); - + double[,] baseterrain1 = GenTerrain(height1); double[,] baseterrain2 = GenTerrain(height2); double[,] t1 = db.LoadTerrain(region1); @@ -986,7 +986,7 @@ namespace OpenSim.Data.Tests public void T303_UpdateTerrain() { TestHelpers.InMethod(); - + double[,] baseterrain1 = GenTerrain(height1); double[,] baseterrain2 = GenTerrain(height2); db.StoreTerrain(baseterrain2, region1); @@ -1003,7 +1003,7 @@ namespace OpenSim.Data.Tests public void T400_EmptyLand() { TestHelpers.InMethod(); - + Assert.That(db.LoadLandObjects(zero).Count, Is.EqualTo(0), "Assert.That(db.LoadLandObjects(zero).Count, Is.EqualTo(0))"); Assert.That(db.LoadLandObjects(region1).Count, Is.EqualTo(0), "Assert.That(db.LoadLandObjects(region1).Count, Is.EqualTo(0))"); Assert.That(db.LoadLandObjects(region2).Count, Is.EqualTo(0), "Assert.That(db.LoadLandObjects(region2).Count, Is.EqualTo(0))"); @@ -1025,15 +1025,15 @@ namespace OpenSim.Data.Tests for (int x = 0; x < Constants.RegionSize; x++) for (int y = 0; y < Constants.RegionSize; y++) terret[x,y] = value; - + return terret; } - + private bool CompareTerrain(double[,] one, double[,] two) { for (int x = 0; x < Constants.RegionSize; x++) for (int y = 0; y < Constants.RegionSize; y++) - if (one[x,y] != two[x,y]) + if (one[x,y] != two[x,y]) return false; return true; @@ -1053,12 +1053,12 @@ namespace OpenSim.Data.Tests // common failure case is people adding new fields that aren't // initialized, but have non-null db constraints. We should // honestly be passing more and more null things in here. - // - // Please note that in Sqlite.BuildPrim there is a commented out inline version + // + // Please note that in Sqlite.BuildPrim there is a commented out inline version // of this so you can debug and step through the build process and check the fields - // + // // Real World Value: Tests for situation where extending a SceneObjectGroup/SceneObjectPart - // causes the application to crash at the database layer because of null values + // causes the application to crash at the database layer because of null values // in NOT NULL fields // private SceneObjectGroup NewSOG(string name, UUID uuid, UUID regionId) @@ -1082,7 +1082,7 @@ namespace OpenSim.Data.Tests return sog; } - + private SceneObjectPart NewSOP(string name, UUID uuid) { SceneObjectPart sop = new SceneObjectPart(); @@ -1096,7 +1096,7 @@ namespace OpenSim.Data.Tests return sop; } - // These are copied from the Inventory Item tests + // These are copied from the Inventory Item tests private InventoryItemBase NewItem(UUID id, UUID parent, UUID owner, string name, UUID asset) { @@ -1114,7 +1114,7 @@ namespace OpenSim.Data.Tests private static string RandomName() { StringBuilder name = new StringBuilder(); - int size = random.Next(5,12); + int size = random.Next(5,12); char ch ; for (int i=0; i - /// Number given to the client when they log-in that they provide + /// Number given to the client when they log-in that they provide /// as credentials to the UDP server /// public uint circuitcode; @@ -328,7 +328,7 @@ namespace OpenSim.Framework Vector3.TryParse(args["start_pos"].AsString(), out startpos); //m_log.InfoFormat("[AGENTCIRCUITDATA]: agentid={0}, child={1}, startpos={2}", AgentID, child, startpos); - + try { // Unpack various appearance elements @@ -353,7 +353,7 @@ namespace OpenSim.Framework { m_log.ErrorFormat("[AGENTCIRCUITDATA] failed to unpack appearance; {0}",e.Message); } - + ServiceURLs = new Dictionary(); // Try parse the new way, OSDMap if (args.ContainsKey("serviceurls") && args["serviceurls"] != null && (args["serviceurls"]).Type == OSDType.Map) diff --git a/OpenSim/Framework/AnimationSet.cs b/OpenSim/Framework/AnimationSet.cs index 6c5b15c11f..87c4a78ea9 100644 --- a/OpenSim/Framework/AnimationSet.cs +++ b/OpenSim/Framework/AnimationSet.cs @@ -84,7 +84,7 @@ namespace OpenSim.Framework it.GroupPermissions = 0; it.EveryOnePermissions = 0; } - + public int AnimationCount { get; private set; } private Dictionary> m_animations = new Dictionary>(); diff --git a/OpenSim/Framework/AssetBase.cs b/OpenSim/Framework/AssetBase.cs index 87fd04affe..88edf2f802 100644 --- a/OpenSim/Framework/AssetBase.cs +++ b/OpenSim/Framework/AssetBase.cs @@ -112,7 +112,7 @@ namespace OpenSim.Framework { get { - return + return IsTextualAsset && ( Type != (sbyte)AssetType.Notecard && Type != (sbyte)AssetType.CallingCard @@ -137,7 +137,7 @@ namespace OpenSim.Framework { get { - return + return (Type == (sbyte)AssetType.Animation || Type == (sbyte)AssetType.Gesture || Type == (sbyte)AssetType.Simstate || @@ -282,7 +282,7 @@ namespace OpenSim.Framework return m_id; } - + set { UUID uuid = UUID.Zero; diff --git a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs index d269e5ded9..b6ea077b33 100644 --- a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Framework.AssetLoader.Filesystem")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,7 +25,7 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/Framework/AssetRequestToClient.cs b/OpenSim/Framework/AssetRequestToClient.cs index d602c1f9b6..3dfbb91982 100644 --- a/OpenSim/Framework/AssetRequestToClient.cs +++ b/OpenSim/Framework/AssetRequestToClient.cs @@ -31,10 +31,10 @@ namespace OpenSim.Framework { /// /// This class was created to refactor OutPacket out of AssetCache - /// There is a conflict between + /// There is a conflict between /// OpenSim.Framework.Communications.Cache.AssetRequest and OpenSim.Framework.AssetRequest - /// and unifying them results in a prebuild chicken and egg problem with OpenSim.Framework requiring - /// OpenSim.Framework.Communications.Cache while OpenSim.Framework.Communications.Cache + /// and unifying them results in a prebuild chicken and egg problem with OpenSim.Framework requiring + /// OpenSim.Framework.Communications.Cache while OpenSim.Framework.Communications.Cache /// requiring OpenSim.Framework /// public class AssetRequestToClient diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index 07c739d569..77a7621a29 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -53,7 +53,7 @@ namespace OpenSim.Framework // should be only used as initial default value ( V1 viewers ) public readonly static int VISUALPARAM_COUNT = 218; -// public readonly static int TEXTURE_COUNT = 21 +// public readonly static int TEXTURE_COUNT = 21 // 21 bad, make it be updated as libovm gets update // also keeping in sync with it public readonly static int TEXTURE_COUNT = Primitive.TextureEntry.MAX_FACES; @@ -121,7 +121,7 @@ namespace OpenSim.Framework get { return m_avatarHeight; } set { m_avatarHeight = value; } } - + public virtual WearableCacheItem[] WearableCacheItems { get { return m_cacheitems; } @@ -219,7 +219,7 @@ namespace OpenSim.Framework m_wearables[i] = new AvatarWearable(); AvatarWearable wearable = appearance.Wearables[i]; for (int j = 0; j < wearable.Count; j++) - m_wearables[i].Add(wearable[j].ItemID, wearable[j].AssetID); + m_wearables[i].Add(wearable[j].ItemID, wearable[j].AssetID); } } else @@ -291,18 +291,18 @@ namespace OpenSim.Framework public virtual void ResetAppearance() { // m_log.WarnFormat("[AVATAR APPEARANCE]: Reset appearance"); - + m_serial = 0; SetDefaultTexture(); - + //for (int i = 0; i < BAKE_INDICES.Length; i++) // { // int idx = BAKE_INDICES[i]; // m_texture.FaceTextures[idx].TextureID = UUID.Zero; // } } - + protected virtual void SetDefaultParams() { m_visualparams = new byte[] { 33,61,85,23,58,127,63,85,63,42,0,85,63,36,85,95,153,63,34,0,63,109,88,132,63,136,81,85,103,136,127,0,150,150,150,127,0,0,0,0,0,127,0,0,255,127,114,127,99,63,127,140,127,127,0,0,0,191,0,104,0,0,0,0,0,0,0,0,0,145,216,133,0,127,0,127,170,0,0,127,127,109,85,127,127,63,85,42,150,150,150,150,150,150,150,25,150,150,150,0,127,0,0,144,85,127,132,127,85,0,127,127,127,127,127,127,59,127,85,127,127,106,47,79,127,127,204,2,141,66,0,0,127,127,0,0,0,0,127,0,159,0,0,178,127,36,85,131,127,127,127,153,95,0,140,75,27,127,127,0,150,150,198,0,0,63,30,127,165,209,198,127,127,153,204,51,51,255,255,255,204,0,255,150,150,150,150,150,150,150,150,150,150,0,150,150,150,150,150,0,127,127,150,150,150,150,150,150,150,150,0,0,150,51,132,150,150,150 }; @@ -319,14 +319,14 @@ namespace OpenSim.Framework public virtual void ResetBakedTextures() { SetDefaultTexture(); - + //for (int i = 0; i < BAKE_INDICES.Length; i++) // { // int idx = BAKE_INDICES[i]; // m_texture.FaceTextures[idx].TextureID = UUID.Zero; // } } - + protected virtual void SetDefaultTexture() { m_texture = new Primitive.TextureEntry(new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE)); @@ -371,7 +371,7 @@ namespace OpenSim.Framework } m_texture = textureEntry; - + return changed; } @@ -531,14 +531,14 @@ namespace OpenSim.Framework { lock (m_attachments) { - List alist = new List(); + List alist = new List(); foreach (KeyValuePair> kvp in m_attachments) { foreach (AvatarAttachment attach in kvp.Value) alist.Add(new AvatarAttachment(attach)); } - return alist; - } + return alist; + } } internal void AppendAttachment(AvatarAttachment attach) @@ -551,7 +551,7 @@ namespace OpenSim.Framework { if (!m_attachments.ContainsKey(attach.AttachPoint)) m_attachments[attach.AttachPoint] = new List(); - + foreach (AvatarAttachment prev in m_attachments[attach.AttachPoint]) { if (prev.ItemID == attach.ItemID) @@ -608,7 +608,7 @@ namespace OpenSim.Framework m_attachments.Remove(attachpoint); return true; } - + return false; } @@ -622,13 +622,13 @@ namespace OpenSim.Framework if (existingAttachment != null) { // m_log.DebugFormat( -// "[AVATAR APPEARANCE]: Found existing attachment for {0}, asset {1} at point {2}", +// "[AVATAR APPEARANCE]: Found existing attachment for {0}, asset {1} at point {2}", // existingAttachment.ItemID, existingAttachment.AssetID, existingAttachment.AttachPoint); if (existingAttachment.AssetID != UUID.Zero && existingAttachment.AttachPoint == (attachpoint & 0x7F)) { m_log.DebugFormat( - "[AVATAR APPEARANCE]: Ignoring attempt to attach an already attached item {0} at point {1}", + "[AVATAR APPEARANCE]: Ignoring attempt to attach an already attached item {0} at point {1}", item, attachpoint); return false; @@ -640,7 +640,7 @@ namespace OpenSim.Framework DetachAttachment(existingAttachment.ItemID); } } - + // check if this is an append or a replace, 0x80 marks it as an append if ((attachpoint & 0x80) > 0) { @@ -701,16 +701,16 @@ namespace OpenSim.Framework if (index >= 0) { // m_log.DebugFormat( -// "[AVATAR APPEARANCE]: Detaching attachment {0}, index {1}, point {2}", +// "[AVATAR APPEARANCE]: Detaching attachment {0}, index {1}, point {2}", // m_attachments[kvp.Key][index].ItemID, index, m_attachments[kvp.Key][index].AttachPoint); // Remove it from the list of attachments at that attach point m_attachments[kvp.Key].RemoveAt(index); - + // And remove the list if there are no more attachments here if (m_attachments[kvp.Key].Count == 0) m_attachments.Remove(kvp.Key); - + return true; } } @@ -867,7 +867,7 @@ namespace OpenSim.Framework { AvatarAttachment att = new AvatarAttachment((OSDMap)attachs[i]); AppendAttachment(att); - + // m_log.DebugFormat( // "[AVATAR APPEARANCE]: Unpacked attachment itemID {0}, assetID {1}, point {2}", // att.ItemID, att.AssetID, att.AttachPoint); @@ -1644,14 +1644,14 @@ namespace OpenSim.Framework SHAPE_EYELID_INNER_CORNER_UP = 214, SKIRT_SKIRT_RED = 215, SKIRT_SKIRT_GREEN = 216, - SKIRT_SKIRT_BLUE = 217, + SKIRT_SKIRT_BLUE = 217, /// /// Avatar Physics section. These are 0 type visual params which get transmitted. /// /// - /// Breast Part 1 + /// Breast Part 1 /// BREAST_PHYSICS_MASS = 218, BREAST_PHYSICS_GRAVITY = 219, @@ -1697,7 +1697,7 @@ namespace OpenSim.Framework BREAST_PHYSICS_LEFTRIGHT_GAIN = 249, BREAST_PHYSICS_LEFTRIGHT_DAMPING = 250, - // Ubit: 07/96/2013 new parameters + // Ubit: 07/96/2013 new parameters _APPEARANCEMESSAGE_VERSION = 251, //ID 11000 SHAPE_HOVER = 252, //ID 11001 diff --git a/OpenSim/Framework/AvatarWearable.cs b/OpenSim/Framework/AvatarWearable.cs index 7bc46edea9..0e8f9608f0 100644 --- a/OpenSim/Framework/AvatarWearable.cs +++ b/OpenSim/Framework/AvatarWearable.cs @@ -96,7 +96,7 @@ namespace OpenSim.Framework // public static readonly UUID DEFAULT_TATTOO_ITEM = new UUID("c47e22bd-3021-4ba4-82aa-2b5cb34d35e1"); // public static readonly UUID DEFAULT_TATTOO_ASSET = new UUID("00000000-0000-2222-3333-100000001007"); - + protected Dictionary m_items = new Dictionary(); protected List m_ids = new List(); @@ -234,10 +234,10 @@ namespace OpenSim.Framework { defaultWearables[i] = new AvatarWearable(); } - + // Body defaultWearables[BODY].Add(DEFAULT_BODY_ITEM, DEFAULT_BODY_ASSET); - + // Hair defaultWearables[HAIR].Add(DEFAULT_HAIR_ITEM, DEFAULT_HAIR_ASSET); @@ -252,7 +252,7 @@ namespace OpenSim.Framework // Pants defaultWearables[PANTS].Add(DEFAULT_PANTS_ITEM, DEFAULT_PANTS_ASSET); - + // // Alpha // defaultWearables[ALPHA].Add(DEFAULT_ALPHA_ITEM, DEFAULT_ALPHA_ASSET); diff --git a/OpenSim/Framework/BasicDOSProtector.cs b/OpenSim/Framework/BasicDOSProtector.cs index 89bfa94191..f1ff18f5cb 100644 --- a/OpenSim/Framework/BasicDOSProtector.cs +++ b/OpenSim/Framework/BasicDOSProtector.cs @@ -31,7 +31,7 @@ using log4net; namespace OpenSim.Framework { - + public class BasicDOSProtector { public enum ThrottleAction @@ -43,7 +43,7 @@ namespace OpenSim.Framework private readonly BasicDosProtectorOptions _options; private readonly Dictionary> _deeperInspection; // per client request checker private readonly Dictionary _tempBlocked; // blocked list - private readonly Dictionary _sessions; + private readonly Dictionary _sessions; private readonly System.Timers.Timer _forgetTimer; // Cleanup timer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private readonly System.Threading.ReaderWriterLockSlim _blockLockSlim = new System.Threading.ReaderWriterLockSlim(); @@ -133,7 +133,7 @@ namespace OpenSim.Framework else throw new System.Security.SecurityException("Throttled"); } - + _blockLockSlim.ExitReadLock(); lock (_generalRequestTimes) @@ -169,10 +169,10 @@ namespace OpenSim.Framework _blockLockSlim.ExitWriteLock(); } - + } - else + else ProcessConcurrency(key, endpoint); } if (_generalRequestTimes.Size == _generalRequestTimes.Capacity && @@ -194,7 +194,7 @@ namespace OpenSim.Framework _sessionLockSlim.EnterWriteLock(); if (_sessions.ContainsKey(key)) _sessions[key] = _sessions[key] + 1; - else + else _sessions.Add(key,1); _sessionLockSlim.ExitWriteLock(); } @@ -209,7 +209,7 @@ namespace OpenSim.Framework } else _sessions.Add(key, 1); - + _sessionLockSlim.ExitWriteLock(); } diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index f6861e49d2..2461049107 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -65,7 +65,7 @@ namespace OpenSim.Framework if (m_pqueue.Count > 0) return m_pqueue.Dequeue(); - + if (m_queue.Count > 0) return m_queue.Dequeue(); return default(T); diff --git a/OpenSim/Framework/Cache.cs b/OpenSim/Framework/Cache.cs index 80f5ff44ee..7ccc320acd 100644 --- a/OpenSim/Framework/Cache.cs +++ b/OpenSim/Framework/Cache.cs @@ -356,10 +356,10 @@ namespace OpenSim.Framework Expire(true); return null; } - + item.hits++; item.lastUsed = DateTime.UtcNow; - + Expire(true); } diff --git a/OpenSim/Framework/CapsUtil.cs b/OpenSim/Framework/CapsUtil.cs index 4baf505784..020f6e26bd 100644 --- a/OpenSim/Framework/CapsUtil.cs +++ b/OpenSim/Framework/CapsUtil.cs @@ -43,7 +43,7 @@ namespace OpenSim.Framework { return "CAPS/" + capsObjectPath + "0000/"; } - + /// /// Get a random CAPS object path component that will be used as the identifying part of all future CAPS requests /// diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index 61c870eb5d..0e5eaf218d 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs @@ -332,7 +332,7 @@ namespace OpenSim.Framework public Vector3 UpAxis; /// - /// Signal on a V2 teleport that Scene.IncomingChildAgentDataUpdate(AgentData ad) should wait for the + /// Signal on a V2 teleport that Scene.IncomingChildAgentDataUpdate(AgentData ad) should wait for the /// scene presence to become root (triggered when the viewer sends a CompleteAgentMovement UDP packet after /// establishing the connection triggered by it's receipt of a TeleportFinish EQ message). /// @@ -434,7 +434,7 @@ namespace OpenSim.Framework args["active_group_name"] = OSD.FromString(ActiveGroupName); if(ActiveGroupTitle != null) args["active_group_title"] = OSD.FromString(ActiveGroupTitle); - + if (ChildrenCapSeeds != null && ChildrenCapSeeds.Count > 0) { OSDArray childrenSeeds = new OSDArray(ChildrenCapSeeds.Count); @@ -623,7 +623,7 @@ namespace OpenSim.Framework if (args.ContainsKey("active_group_name") && args["active_group_name"] != null) ActiveGroupName = args["active_group_name"].AsString(); - + if(args.ContainsKey("active_group_title") && args["active_group_title"] != null) ActiveGroupTitle = args["active_group_title"].AsString(); @@ -843,7 +843,7 @@ namespace OpenSim.Framework public class CompleteAgentData : AgentData { - public override OSDMap Pack(EntityTransferContext ctx) + public override OSDMap Pack(EntityTransferContext ctx) { return base.Pack(ctx); } diff --git a/OpenSim/Framework/CircularBuffer.cs b/OpenSim/Framework/CircularBuffer.cs index e919337a70..e101938bab 100644 --- a/OpenSim/Framework/CircularBuffer.cs +++ b/OpenSim/Framework/CircularBuffer.cs @@ -1,21 +1,21 @@ /* -Copyright (c) 2012, Alex Regueiro +Copyright (c) 2012, Alex Regueiro All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +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 +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. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR 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 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR 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; using System.Collections.Generic; diff --git a/OpenSim/Framework/CnmMemoryCache.cs b/OpenSim/Framework/CnmMemoryCache.cs index 92af331102..f996cb0bd0 100644 --- a/OpenSim/Framework/CnmMemoryCache.cs +++ b/OpenSim/Framework/CnmMemoryCache.cs @@ -36,14 +36,14 @@ namespace OpenSim.Framework /// Cenome memory based cache to store key/value pairs (elements) limited time and/or limited size. /// /// - /// The type of keys in the cache. + /// The type of keys in the cache. /// /// - /// The type of values in the dictionary. + /// The type of values in the dictionary. /// /// /// - /// Cenome memory cache stores elements to hash table generations. When new element is being added to cache, and new size would exceed + /// Cenome memory cache stores elements to hash table generations. When new element is being added to cache, and new size would exceed /// maximal allowed size or maximal amount of allowed element count, then elements in oldest generation are deleted. Last access time /// is also tracked in generation level - thus it is possible that some elements are staying in cache far beyond their expiration time. /// If elements in older generations are accessed through method, they are moved to newest generation. @@ -176,7 +176,7 @@ namespace OpenSim.Framework } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// Maximal cache size. @@ -201,7 +201,7 @@ namespace OpenSim.Framework } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// Maximal cache size. @@ -218,7 +218,7 @@ namespace OpenSim.Framework } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// Maximal cache size. @@ -336,7 +336,7 @@ namespace OpenSim.Framework /// private void CheckExpired() { - // Do this only one in every m_operationsBetweenTimeChecks + // Do this only one in every m_operationsBetweenTimeChecks // Fetching time is using several millisecons - it is better not to do all time. m_operationsBetweenTimeChecks--; if (m_operationsBetweenTimeChecks <= 0) @@ -394,7 +394,7 @@ namespace OpenSim.Framework new IEnumerator>[2]; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// The cache. @@ -456,7 +456,7 @@ namespace OpenSim.Framework /// if the enumerator was successfully advanced to the next element; if the enumerator has passed the end of the collection. /// /// - /// The collection was modified after the enumerator was created. + /// The collection was modified after the enumerator was created. /// /// 2 public bool MoveNext() @@ -479,7 +479,7 @@ namespace OpenSim.Framework /// Sets the enumerator to its initial position, which is before the first element in the collection. /// /// - /// The collection was modified after the enumerator was created. + /// The collection was modified after the enumerator was created. /// /// 2 public void Reset() @@ -548,7 +548,7 @@ namespace OpenSim.Framework private DateTime m_expirationTime1; /// - /// Index to first free element. + /// Index to first free element. /// private int m_firstFreeElement; @@ -681,8 +681,8 @@ namespace OpenSim.Framework /// Next element in chain. /// /// - /// When element have value (something is stored to it), this is index of - /// next element with same bucket index. When element is free, this + /// When element have value (something is stored to it), this is index of + /// next element with same bucket index. When element is free, this /// is index of next element in free element's list. /// public int Next; @@ -696,7 +696,7 @@ namespace OpenSim.Framework public long Size; /// - /// Element's value. + /// Element's value. /// /// /// It is possible that this value is even when element @@ -812,7 +812,7 @@ namespace OpenSim.Framework /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. /// /// - /// The collection was modified after the enumerator was created. + /// The collection was modified after the enumerator was created. /// public bool MoveNext() { @@ -841,7 +841,7 @@ namespace OpenSim.Framework /// Sets the enumerator to its initial position, which is before the first element in the collection. /// /// - /// The collection was modified after the enumerator was created. + /// The collection was modified after the enumerator was created. /// /// 2 public void Reset() @@ -931,7 +931,7 @@ namespace OpenSim.Framework /// The key to locate in the . /// /// - /// if the contains an element with the ; + /// if the contains an element with the ; /// otherwise . /// public bool Contains(int bucketIndex, TKey key) @@ -1014,7 +1014,7 @@ namespace OpenSim.Framework /// /// /// - /// If element was already existing in generation and new element size fits to collection limits, + /// If element was already existing in generation and new element size fits to collection limits, /// then it's value is replaced with new one and size information is updated. If element didn't /// exists in generation before, then generation must have empty space for a new element and /// size must fit generation's limits, before element is added to generation. @@ -1070,7 +1070,7 @@ namespace OpenSim.Framework if (Size - m_elements[ elementIndex ].Size + size > m_cache.m_generationMaxSize) { // Generation is full - // Remove existing element, because generation is going to be recycled to + // Remove existing element, because generation is going to be recycled to // old generation and element is stored to new generation RemoveElement(bucketIndex, elementIndex, previousIndex); return false; @@ -1110,12 +1110,12 @@ namespace OpenSim.Framework /// /// /// If element is not found from generation then and - /// are set to default value (default(TValue) and 0). + /// are set to default value (default(TValue) and 0). /// /// public bool TryGetValue(int bucketIndex, TKey key, out TValue value, out long size) { - // Find entry index, + // Find entry index, int previousIndex; int elementIndex = FindElementIndex(bucketIndex, key, m_newGeneration, out previousIndex); if (elementIndex == -1) @@ -1166,7 +1166,7 @@ namespace OpenSim.Framework /// /// /// There are two kind generations: "new generation" and "old generation(s)". All new elements - /// are added to "new generation". + /// are added to "new generation". /// /// protected interface IGeneration : IEnumerable> @@ -1211,7 +1211,7 @@ namespace OpenSim.Framework /// The key to locate in the . /// /// - /// if the contains an element with the ; + /// if the contains an element with the ; /// otherwise . /// bool Contains(int bucketIndex, TKey key); @@ -1259,7 +1259,7 @@ namespace OpenSim.Framework /// /// /// - /// If element was already existing in generation and new element size fits to collection limits, + /// If element was already existing in generation and new element size fits to collection limits, /// then it's value is replaced with new one and size information is updated. If element didn't /// exists in generation before, then generation must have empty space for a new element and /// size must fit generation's limits, before element is added to generation. @@ -1288,7 +1288,7 @@ namespace OpenSim.Framework /// /// /// If element is not found from generation then and - /// are set to default value (default(TValue) and 0). + /// are set to default value (default(TValue) and 0). /// /// bool TryGetValue(int bucketIndex, TKey key, out TValue value, out long size); @@ -1303,8 +1303,8 @@ namespace OpenSim.Framework /// /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -1324,13 +1324,13 @@ namespace OpenSim.Framework /// /// /// - /// When element has been stored in longer than - /// and it is not accessed through method or element's value is - /// not replaced by method, then it is automatically removed from the + /// When element has been stored in longer than + /// and it is not accessed through method or element's value is + /// not replaced by method, then it is automatically removed from the /// . /// /// - /// It is possible that implementation removes element before it's expiration time, + /// It is possible that implementation removes element before it's expiration time, /// because total size or count of elements stored to cache is larger than or . /// /// @@ -1375,17 +1375,17 @@ namespace OpenSim.Framework /// Gets a value indicating whether is limiting count of elements. /// /// - /// if the count of elements is limited; - /// otherwise, . + /// if the count of elements is limited; + /// otherwise, . /// /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// /// - /// + /// /// /// public bool IsCountLimited @@ -1397,13 +1397,13 @@ namespace OpenSim.Framework /// Gets a value indicating whether is limiting size of elements. /// /// - /// if the total size of elements is limited; - /// otherwise, . + /// if the total size of elements is limited; + /// otherwise, . /// /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -1420,12 +1420,12 @@ namespace OpenSim.Framework /// Gets a value indicating whether or not access to the is synchronized (thread safe). /// /// - /// if access to the is synchronized (thread safe); - /// otherwise, . + /// if access to the is synchronized (thread safe); + /// otherwise, . /// /// /// - /// To get synchronized (thread safe) access to object, use + /// To get synchronized (thread safe) access to object, use /// in class /// to retrieve synchronized wrapper for object. /// @@ -1441,13 +1441,13 @@ namespace OpenSim.Framework /// Gets a value indicating whether elements stored to have limited inactivity time. /// /// - /// if the has a fixed total size of elements; - /// otherwise, . + /// if the has a fixed total size of elements; + /// otherwise, . /// /// /// If have limited inactivity time and element is not accessed through - /// or methods in , then element is automatically removed from - /// the cache. Depending on implementation of the , some of the elements may + /// or methods in , then element is automatically removed from + /// the cache. Depending on implementation of the , some of the elements may /// stay longer in cache. /// /// @@ -1463,13 +1463,13 @@ namespace OpenSim.Framework /// Gets or sets maximal allowed count of elements that can be stored to . /// /// - /// , if is not limited by count of elements; + /// , if is not limited by count of elements; /// otherwise maximal allowed count of elements. /// /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// public int MaxCount @@ -1496,7 +1496,7 @@ namespace OpenSim.Framework /// /// /// - /// If element's size is larger than , then element is + /// If element's size is larger than , then element is /// not added to the . /// /// @@ -1522,8 +1522,8 @@ namespace OpenSim.Framework /// Normally size is total bytes used by elements in the cache. But it can be any other suitable unit of measure. /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -1556,11 +1556,11 @@ namespace OpenSim.Framework /// Normally bytes, but can be any suitable unit of measure. /// /// - /// Element's size is given when element is added or replaced by method. + /// Element's size is given when element is added or replaced by method. /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -1581,8 +1581,8 @@ namespace OpenSim.Framework /// /// /// - /// To get synchronized (thread safe) access to , use - /// method to retrieve synchronized wrapper interface to + /// To get synchronized (thread safe) access to , use + /// method to retrieve synchronized wrapper interface to /// . /// /// @@ -1735,7 +1735,7 @@ namespace OpenSim.Framework } /// - /// Add or replace an element with the provided , and to + /// Add or replace an element with the provided , and to /// . /// /// @@ -1748,7 +1748,7 @@ namespace OpenSim.Framework /// The element's size. Normally bytes, but can be any suitable unit of measure. /// /// - /// if element has been added successfully to the ; + /// if element has been added successfully to the ; /// otherwise . /// /// @@ -1759,17 +1759,17 @@ namespace OpenSim.Framework /// /// /// - /// If element's is larger than , then element is - /// not added to the , however - possible older element is - /// removed from the . + /// If element's is larger than , then element is + /// not added to the , however - possible older element is + /// removed from the . /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -1809,15 +1809,15 @@ namespace OpenSim.Framework /// Gets the associated with the specified . /// /// - /// if the contains an element with + /// if the contains an element with /// the specified key; otherwise, . /// /// /// The key whose to get. /// /// - /// When this method returns, the value associated with the specified , - /// if the is found; otherwise, the + /// When this method returns, the value associated with the specified , + /// if the is found; otherwise, the /// default value for the type of the parameter. This parameter is passed uninitialized. /// /// diff --git a/OpenSim/Framework/CnmSynchronizedCache.cs b/OpenSim/Framework/CnmSynchronizedCache.cs index 2bafbe98a7..b33f4f70a9 100644 --- a/OpenSim/Framework/CnmSynchronizedCache.cs +++ b/OpenSim/Framework/CnmSynchronizedCache.cs @@ -36,10 +36,10 @@ namespace OpenSim.Framework /// Synchronized Cenome cache wrapper. /// /// - /// The type of keys in the cache. + /// The type of keys in the cache. /// /// - /// The type of values in the cache. + /// The type of values in the cache. /// /// /// @@ -60,7 +60,7 @@ namespace OpenSim.Framework private readonly object m_syncRoot; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// Initializes a new instance of the class. /// /// @@ -73,13 +73,13 @@ namespace OpenSim.Framework } /// - /// Returns a wrapper that is synchronized (thread safe). + /// Returns a wrapper that is synchronized (thread safe). /// /// /// The to synchronize. /// /// - /// A wrapper that is synchronized (thread safe). + /// A wrapper that is synchronized (thread safe). /// /// /// is null. @@ -125,7 +125,7 @@ namespace OpenSim.Framework } /// - /// Finalizes an instance of the class. + /// Finalizes an instance of the class. /// ~SynchronizedEnumerator() { @@ -184,7 +184,7 @@ namespace OpenSim.Framework /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. /// /// - /// The collection was modified after the enumerator was created. + /// The collection was modified after the enumerator was created. /// public bool MoveNext() { @@ -195,7 +195,7 @@ namespace OpenSim.Framework /// Sets the enumerator to its initial position, which is before the first element in the collection. /// /// - /// The collection was modified after the enumerator was created. + /// The collection was modified after the enumerator was created. /// public void Reset() { @@ -214,8 +214,8 @@ namespace OpenSim.Framework /// /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -241,13 +241,13 @@ namespace OpenSim.Framework /// /// /// - /// When element has been stored in longer than - /// and it is not accessed through method or element's value is - /// not replaced by method, then it is automatically removed from the + /// When element has been stored in longer than + /// and it is not accessed through method or element's value is + /// not replaced by method, then it is automatically removed from the /// . /// /// - /// It is possible that implementation removes element before it's expiration time, + /// It is possible that implementation removes element before it's expiration time, /// because total size or count of elements stored to cache is larger than or . /// /// @@ -291,17 +291,17 @@ namespace OpenSim.Framework /// Gets a value indicating whether is limiting count of elements. /// /// - /// if the count of elements is limited; - /// otherwise, . + /// if the count of elements is limited; + /// otherwise, . /// /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// /// - /// + /// /// /// public bool IsCountLimited @@ -319,13 +319,13 @@ namespace OpenSim.Framework /// Gets a value indicating whether is limiting size of elements. /// /// - /// if the total size of elements is limited; - /// otherwise, . + /// if the total size of elements is limited; + /// otherwise, . /// /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -348,12 +348,12 @@ namespace OpenSim.Framework /// Gets a value indicating whether or not access to the is synchronized (thread safe). /// /// - /// if access to the is synchronized (thread safe); - /// otherwise, . + /// if access to the is synchronized (thread safe); + /// otherwise, . /// /// /// - /// To get synchronized (thread safe) access to object, use + /// To get synchronized (thread safe) access to object, use /// in class /// to retrieve synchronized wrapper for object. /// @@ -369,13 +369,13 @@ namespace OpenSim.Framework /// Gets a value indicating whether elements stored to have limited inactivity time. /// /// - /// if the has a fixed total size of elements; - /// otherwise, . + /// if the has a fixed total size of elements; + /// otherwise, . /// /// /// If have limited inactivity time and element is not accessed through - /// or methods in , then element is automatically removed from - /// the cache. Depending on implementation of the , some of the elements may + /// or methods in , then element is automatically removed from + /// the cache. Depending on implementation of the , some of the elements may /// stay longer in cache. /// /// @@ -397,13 +397,13 @@ namespace OpenSim.Framework /// Gets or sets maximal allowed count of elements that can be stored to . /// /// - /// , if is not limited by count of elements; + /// , if is not limited by count of elements; /// otherwise maximal allowed count of elements. /// /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// public int MaxCount @@ -433,7 +433,7 @@ namespace OpenSim.Framework /// /// /// - /// If element's size is larger than , then element is + /// If element's size is larger than , then element is /// not added to the . /// /// @@ -463,8 +463,8 @@ namespace OpenSim.Framework /// Normally size is total bytes used by elements in the cache. But it can be any other suitable unit of measure. /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// /// value is less than 0. @@ -501,11 +501,11 @@ namespace OpenSim.Framework /// Normally bytes, but can be any suitable unit of measure. /// /// - /// Element's size is given when element is added or replaced by method. + /// Element's size is given when element is added or replaced by method. /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -532,8 +532,8 @@ namespace OpenSim.Framework /// /// /// - /// To get synchronized (thread safe) access to , use - /// method to retrieve synchronized wrapper interface to + /// To get synchronized (thread safe) access to , use + /// method to retrieve synchronized wrapper interface to /// . /// /// @@ -647,7 +647,7 @@ namespace OpenSim.Framework } /// - /// Add or replace an element with the provided , and to + /// Add or replace an element with the provided , and to /// . /// /// @@ -660,7 +660,7 @@ namespace OpenSim.Framework /// The element's size. Normally bytes, but can be any suitable unit of measure. /// /// - /// if element has been added successfully to the ; + /// if element has been added successfully to the ; /// otherwise . /// /// @@ -671,17 +671,17 @@ namespace OpenSim.Framework /// /// /// - /// If element's is larger than , then element is - /// not added to the , however - possible older element is - /// removed from the . + /// If element's is larger than , then element is + /// not added to the , however - possible older element is + /// removed from the . /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -703,15 +703,15 @@ namespace OpenSim.Framework /// Gets the associated with the specified . /// /// - /// if the contains an element with + /// if the contains an element with /// the specified key; otherwise, . /// /// /// The key whose to get. /// /// - /// When this method returns, the value associated with the specified , - /// if the is found; otherwise, the + /// When this method returns, the value associated with the specified , + /// if the is found; otherwise, the /// default value for the type of the parameter. This parameter is passed uninitialized. /// /// diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs index 6b7cdf8036..52360b40a2 100644 --- a/OpenSim/Framework/Console/CommandConsole.cs +++ b/OpenSim/Framework/Console/CommandConsole.cs @@ -52,27 +52,27 @@ namespace OpenSim.Framework.Console /// The module from which this command comes /// public string module; - + /// /// Whether the module is shared /// public bool shared; - + /// /// Very short BNF description /// public string help_text; - + /// /// Longer one line help text /// public string long_help; - + /// /// Full descriptive help for this command /// public string descriptive_help; - + /// /// The method to invoke for this command /// @@ -106,7 +106,7 @@ namespace OpenSim.Framework.Console { List help = new List(); List helpParts = new List(cmd); - + // Remove initial help keyword helpParts.RemoveAt(0); @@ -154,7 +154,7 @@ namespace OpenSim.Framework.Console return help; } - + /// /// See if we can find the requested command in order to display longer help /// @@ -171,23 +171,23 @@ namespace OpenSim.Framework.Console help.Insert(0, ItemHelpText); return help; } - + Dictionary dict = tree; while (helpParts.Count > 0) { string helpPart = helpParts[0]; - + if (!dict.ContainsKey(helpPart)) break; - + //m_log.Debug("Found {0}", helpParts[0]); - + if (dict[helpPart] is Dictionary) - dict = (Dictionary)dict[helpPart]; - + dict = (Dictionary)dict[helpPart]; + helpParts.RemoveAt(0); } - + // There was a command for the given help string if (dict.ContainsKey(String.Empty)) { @@ -200,14 +200,14 @@ namespace OpenSim.Framework.Console // If we do have some descriptive help then insert a spacing line before for readability. if (descriptiveHelp != string.Empty) help.Add(string.Empty); - + help.Add(commandInfo.descriptive_help); } else { help.Add(string.Format("No help is available for {0}", originalHelpRequest)); } - + return help; } @@ -268,7 +268,7 @@ namespace OpenSim.Framework.Console // } // return result; // } - + /// /// Add a command to those which can be invoked from the console. /// @@ -299,7 +299,7 @@ namespace OpenSim.Framework.Console string[] parts = Parser.Parse(command); Dictionary current = tree; - + foreach (string part in parts) { if (current.ContainsKey(part)) @@ -326,7 +326,7 @@ namespace OpenSim.Framework.Console return; } - + info = new CommandInfo(); info.module = module; info.shared = shared; @@ -471,7 +471,7 @@ namespace OpenSim.Framework.Console return null; } - + public bool HasCommand(string command) { string[] result; diff --git a/OpenSim/Framework/Console/ConsoleBase.cs b/OpenSim/Framework/Console/ConsoleBase.cs index 2d8e723af2..64cddea999 100755 --- a/OpenSim/Framework/Console/ConsoleBase.cs +++ b/OpenSim/Framework/Console/ConsoleBase.cs @@ -67,7 +67,7 @@ namespace OpenSim.Framework.Console { System.Console.WriteLine(text); } - + public virtual void OutputFormat(string format, params object[] components) { Output(string.Format(format, components)); @@ -86,7 +86,7 @@ namespace OpenSim.Framework.Console return ret; } - + public string CmdPrompt(string p, List excludedCharacters) { bool itisdone = false; @@ -95,7 +95,7 @@ namespace OpenSim.Framework.Console { itisdone = true; ret = CmdPrompt(p); - + foreach (char c in excludedCharacters) { if (ret.Contains(c.ToString())) @@ -117,7 +117,7 @@ namespace OpenSim.Framework.Console { itisdone = true; ret = CmdPrompt(p, def); - + if (ret == String.Empty) { ret = def; diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs index 44f6dc193b..bfa05a21ef 100644 --- a/OpenSim/Framework/Console/ConsoleUtil.cs +++ b/OpenSim/Framework/Console/ConsoleUtil.cs @@ -40,7 +40,7 @@ namespace OpenSim.Framework.Console // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public const int LocalIdNotFound = 0; - + /// /// Used by modules to display stock co-ordinate help, though possibly this should be under some general section /// rather than in each help summary. @@ -57,10 +57,10 @@ namespace OpenSim.Framework.Console show object pos ,20,20 to ,40,40 delete object pos ,,30 to ,,~ show object pos ,,-~ to ,,30"; - + public const string MinRawConsoleVectorValue = "-~"; public const string MaxRawConsoleVectorValue = "~"; - + public const string VectorSeparator = ","; public static char[] VectorSeparatorChars = VectorSeparator.ToCharArray(); @@ -81,7 +81,7 @@ namespace OpenSim.Framework.Console return true; } - + /// /// Try to parse a console UUID from the console. /// @@ -101,7 +101,7 @@ namespace OpenSim.Framework.Console return false; } - + return true; } @@ -259,7 +259,7 @@ namespace OpenSim.Framework.Console return false; } - + /// /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 /// @@ -270,7 +270,7 @@ namespace OpenSim.Framework.Console { return TryParseConsoleVector(rawConsoleVector, c => float.MinValue.ToString(), out vector); } - + /// /// Convert a maximum vector input from the console to an OpenMetaverse.Vector3 /// @@ -281,7 +281,7 @@ namespace OpenSim.Framework.Console { return TryParseConsoleVector(rawConsoleVector, c => float.MaxValue.ToString(), out vector); } - + /// /// Convert a vector input from the console to an OpenMetaverse.Vector3 /// @@ -354,10 +354,10 @@ namespace OpenSim.Framework.Console string rawConsoleVector, int dimensions, Func blankComponentFunc) { List components = rawConsoleVector.Split(VectorSeparatorChars).ToList(); - + if (components.Count < 1 || components.Count > dimensions) return null; - + if (components.Count < dimensions) { if (blankComponentFunc == null) @@ -380,7 +380,7 @@ namespace OpenSim.Framework.Console else return c; }); - + return string.Join(VectorSeparator, cookedComponents.ToArray()); } } diff --git a/OpenSim/Framework/Console/LocalConsole.cs b/OpenSim/Framework/Console/LocalConsole.cs index 28293c0dd0..73f0323874 100644 --- a/OpenSim/Framework/Console/LocalConsole.cs +++ b/OpenSim/Framework/Console/LocalConsole.cs @@ -51,7 +51,7 @@ namespace OpenSim.Framework.Console private const string LOGLEVEL_NONE = "(none)"; // Used to extract categories for colourization. - private Regex m_categoryRegex + private Regex m_categoryRegex = new Regex( @"^(?.*?)\[(?[^\]]+)\]:?(?.*)", RegexOptions.Singleline | RegexOptions.Compiled); @@ -167,15 +167,15 @@ namespace OpenSim.Framework.Console { System.Console.CursorLeft = 0; } - else + else { int bufferWidth = System.Console.BufferWidth; - + // On Mono 2.4.2.3 (and possibly above), the buffer value is sometimes erroneously zero (Mantis 4657) if (bufferWidth > 0 && left >= bufferWidth) System.Console.CursorLeft = bufferWidth - 1; } - + if (top < 0) { top = 0; @@ -183,7 +183,7 @@ namespace OpenSim.Framework.Console else { int bufferHeight = System.Console.BufferHeight; - + // On Mono 2.4.2.3 (and possibly above), the buffer value is sometimes erroneously zero (Mantis 4657) if (bufferHeight > 0 && top >= bufferHeight) top = bufferHeight - 1; @@ -216,14 +216,14 @@ namespace OpenSim.Framework.Console { System.Console.CursorTop = 0; } - else + else { int bufferHeight = System.Console.BufferHeight; // On Mono 2.4.2.3 (and possibly above), the buffer value is sometimes erroneously zero (Mantis 4657) if (bufferHeight > 0 && top >= bufferHeight) System.Console.CursorTop = bufferHeight - 1; } - + if (left < 0) { left = 0; @@ -339,7 +339,7 @@ namespace OpenSim.Framework.Console string outText = text; if (level != LOGLEVEL_NONE) - { + { MatchCollection matches = m_categoryRegex.Matches(text); if (matches.Count == 1) @@ -364,7 +364,7 @@ namespace OpenSim.Framework.Console WriteColorText(ConsoleColor.Yellow, outText); else System.Console.Write(outText); - + System.Console.WriteLine(); } @@ -551,7 +551,7 @@ namespace OpenSim.Framework.Console } string commandLine = m_commandLine.ToString(); - + if (isCommand) { string[] cmd = Commands.Resolve(Parser.Parse(commandLine)); @@ -573,7 +573,7 @@ namespace OpenSim.Framework.Console // If we're not echoing to screen (e.g. a password) then we probably don't want it in history if (m_echo && commandLine != "") AddToHistory(commandLine); - + return commandLine; default: break; diff --git a/OpenSim/Framework/Console/MockConsole.cs b/OpenSim/Framework/Console/MockConsole.cs index 1a142df016..e1ff72054e 100644 --- a/OpenSim/Framework/Console/MockConsole.cs +++ b/OpenSim/Framework/Console/MockConsole.cs @@ -35,7 +35,7 @@ namespace OpenSim.Framework.Console { /// /// This is a Fake console that's used when setting up the Scene in Unit Tests - /// Don't use this except for Unit Testing or you're in for a world of hurt when the + /// Don't use this except for Unit Testing or you're in for a world of hurt when the /// sim gets to ReadLine /// public class MockConsole : ICommandConsole @@ -56,7 +56,7 @@ namespace OpenSim.Framework.Console public string ReadLine(string p, bool isCommand, bool e) { return ""; } - public object ConsoleScene { + public object ConsoleScene { get { return null; } set {} } diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs index 9049b4b801..f59c9024be 100644 --- a/OpenSim/Framework/Console/RemoteConsole.cs +++ b/OpenSim/Framework/Console/RemoteConsole.cs @@ -46,93 +46,93 @@ namespace OpenSim.Framework.Console // public class RemoteConsole : CommandConsole { - // Connection specific data, indexed by a session ID - // we create when a client connects. - protected class ConsoleConnection - { - // Last activity from the client - public int last; + // Connection specific data, indexed by a session ID + // we create when a client connects. + protected class ConsoleConnection + { + // Last activity from the client + public int last; - // Last line of scrollback posted to this client - public long lastLineSeen; + // Last line of scrollback posted to this client + public long lastLineSeen; - // True if this is a new connection, e.g. has never - // displayed a prompt to the user. - public bool newConnection = true; - } + // True if this is a new connection, e.g. has never + // displayed a prompt to the user. + public bool newConnection = true; + } - // A line in the scrollback buffer. - protected class ScrollbackEntry - { - // The line number of this entry - public long lineNumber; + // A line in the scrollback buffer. + protected class ScrollbackEntry + { + // The line number of this entry + public long lineNumber; - // The text to send to the client - public string text; + // The text to send to the client + public string text; - // The level this should be logged as. Omitted for - // prompts and input echo. - public string level; + // The level this should be logged as. Omitted for + // prompts and input echo. + public string level; - // True if the text above is a prompt, e.g. the - // client should turn on the cursor / accept input - public bool isPrompt; + // True if the text above is a prompt, e.g. the + // client should turn on the cursor / accept input + public bool isPrompt; - // True if the requested input is a command. A - // client may offer help or validate input if - // this is set. If false, input should be sent - // as typed. - public bool isCommand; + // True if the requested input is a command. A + // client may offer help or validate input if + // this is set. If false, input should be sent + // as typed. + public bool isCommand; - // True if this text represents a line of text that - // was input in response to a prompt. A client should - // turn off the cursor and refrain from sending commands - // until a new prompt is received. - public bool isInput; - } + // True if this text represents a line of text that + // was input in response to a prompt. A client should + // turn off the cursor and refrain from sending commands + // until a new prompt is received. + public bool isInput; + } - // Data that is relevant to all connections + // Data that is relevant to all connections - // The scrollback buffer + // The scrollback buffer protected List m_Scrollback = new List(); - // Monotonously incrementing line number. This may eventually - // wrap. No provision is made for that case because 64 bits - // is a long, long time. + // Monotonously incrementing line number. This may eventually + // wrap. No provision is made for that case because 64 bits + // is a long, long time. protected long m_lineNumber = 0; - // These two variables allow us to send the correct - // information about the prompt status to the client, - // irrespective of what may have run off the top of the - // scrollback buffer; - protected bool m_expectingInput = false; - protected bool m_expectingCommand = true; - protected string m_lastPromptUsed; - - // This is the list of things received from clients. - // Note: Race conditions can happen. If a client sends - // something while nothing is expected, it will be - // intepreted as input to the next prompt. For - // commands this is largely correct. For other prompts, - // YMMV. - // TODO: Find a better way to fix this + // These two variables allow us to send the correct + // information about the prompt status to the client, + // irrespective of what may have run off the top of the + // scrollback buffer; + protected bool m_expectingInput = false; + protected bool m_expectingCommand = true; + protected string m_lastPromptUsed; + + // This is the list of things received from clients. + // Note: Race conditions can happen. If a client sends + // something while nothing is expected, it will be + // intepreted as input to the next prompt. For + // commands this is largely correct. For other prompts, + // YMMV. + // TODO: Find a better way to fix this protected List m_InputData = new List(); - // Event to allow ReadLine to wait synchronously even though - // everthing else is asynchronous here. + // Event to allow ReadLine to wait synchronously even though + // everthing else is asynchronous here. protected ManualResetEvent m_DataEvent = new ManualResetEvent(false); - // The list of sessions we maintain. Unlike other console types, - // multiple users on the same console are explicitly allowed. + // The list of sessions we maintain. Unlike other console types, + // multiple users on the same console are explicitly allowed. protected Dictionary m_Connections = new Dictionary(); - // Timer to control expiration of sessions that have been - // disconnected. - protected System.Timers.Timer m_expireTimer = new System.Timers.Timer(5000); + // Timer to control expiration of sessions that have been + // disconnected. + protected System.Timers.Timer m_expireTimer = new System.Timers.Timer(5000); - // The less interesting stuff that makes the actual server - // work. + // The less interesting stuff that makes the actual server + // work. protected IHttpServer m_Server = null; protected IConfigSource m_Config = null; @@ -143,130 +143,130 @@ namespace OpenSim.Framework.Console public RemoteConsole(string defaultPrompt) : base(defaultPrompt) { - // There is something wrong with this architecture. - // A prompt is sent on every single input, so why have this? - // TODO: Investigate and fix. - m_lastPromptUsed = defaultPrompt; + // There is something wrong with this architecture. + // A prompt is sent on every single input, so why have this? + // TODO: Investigate and fix. + m_lastPromptUsed = defaultPrompt; - // Start expiration of sesssions. - m_expireTimer.Elapsed += DoExpire; - m_expireTimer.Start(); + // Start expiration of sesssions. + m_expireTimer.Elapsed += DoExpire; + m_expireTimer.Start(); } public void ReadConfig(IConfigSource config) { m_Config = config; - // We're pulling this from the 'Network' section for legacy - // compatibility. However, this is so essentially insecure - // that TLS and client certs should be used instead of - // a username / password. + // We're pulling this from the 'Network' section for legacy + // compatibility. However, this is so essentially insecure + // that TLS and client certs should be used instead of + // a username / password. IConfig netConfig = m_Config.Configs["Network"]; if (netConfig == null) return; - // Get the username and password. + // Get the username and password. m_UserName = netConfig.GetString("ConsoleUser", String.Empty); m_Password = netConfig.GetString("ConsolePass", String.Empty); - // Woefully underdocumented, this is what makes javascript - // console clients work. Set to "*" for anywhere or (better) - // to specific addresses. + // Woefully underdocumented, this is what makes javascript + // console clients work. Set to "*" for anywhere or (better) + // to specific addresses. m_AllowedOrigin = netConfig.GetString("ConsoleAllowedOrigin", String.Empty); } public void SetServer(IHttpServer server) { - // This is called by the framework to give us the server - // instance (means: port) to work with. + // This is called by the framework to give us the server + // instance (means: port) to work with. m_Server = server; - // Add our handlers + // Add our handlers m_Server.AddHTTPHandler("/StartSession/", HandleHttpStartSession); m_Server.AddHTTPHandler("/CloseSession/", HandleHttpCloseSession); m_Server.AddHTTPHandler("/SessionCommand/", HandleHttpSessionCommand); } public override void Output(string text, string level) - { - Output(text, level, false, false, false); - } + { + Output(text, level, false, false, false); + } protected void Output(string text, string level, bool isPrompt, bool isCommand, bool isInput) { - // Increment the line number. It was 0 and they start at 1 - // so we need to pre-increment. - m_lineNumber++; + // Increment the line number. It was 0 and they start at 1 + // so we need to pre-increment. + m_lineNumber++; - // Create and populate the new entry. - ScrollbackEntry newEntry = new ScrollbackEntry(); + // Create and populate the new entry. + ScrollbackEntry newEntry = new ScrollbackEntry(); - newEntry.lineNumber = m_lineNumber; - newEntry.text = text; - newEntry.level = level; - newEntry.isPrompt = isPrompt; - newEntry.isCommand = isCommand; - newEntry.isInput = isInput; + newEntry.lineNumber = m_lineNumber; + newEntry.text = text; + newEntry.level = level; + newEntry.isPrompt = isPrompt; + newEntry.isCommand = isCommand; + newEntry.isInput = isInput; - // Add a line to the scrollback. In some cases, that may not - // actually be a line of text. + // Add a line to the scrollback. In some cases, that may not + // actually be a line of text. lock (m_Scrollback) { - // Prune the scrollback to the length se send as connect - // burst to give the user some context. + // Prune the scrollback to the length se send as connect + // burst to give the user some context. while (m_Scrollback.Count >= 1000) m_Scrollback.RemoveAt(0); m_Scrollback.Add(newEntry); } - // Let the rest of the system know we have output something. + // Let the rest of the system know we have output something. FireOnOutput(text.Trim()); - // Also display it for debugging. + // Also display it for debugging. System.Console.WriteLine(text.Trim()); } public override void Output(string text) { - // Output plain (non-logging style) text. + // Output plain (non-logging style) text. Output(text, String.Empty, false, false, false); } public override string ReadLine(string p, bool isCommand, bool e) { - // Output the prompt an prepare to wait. This - // is called on a dedicated console thread and - // needs to be synchronous. Old architecture but - // not worth upgrading. - if (isCommand) - { - m_expectingInput = true; - m_expectingCommand = true; + // Output the prompt an prepare to wait. This + // is called on a dedicated console thread and + // needs to be synchronous. Old architecture but + // not worth upgrading. + if (isCommand) + { + m_expectingInput = true; + m_expectingCommand = true; Output(p, String.Empty, true, true, false); - m_lastPromptUsed = p; - } - else - { - m_expectingInput = true; + m_lastPromptUsed = p; + } + else + { + m_expectingInput = true; Output(p, String.Empty, true, false, false); - } + } - // Here is where we wait for the user to input something. + // Here is where we wait for the user to input something. m_DataEvent.WaitOne(); string cmdinput; - // Check for empty input. Read input if not empty. + // Check for empty input. Read input if not empty. lock (m_InputData) { if (m_InputData.Count == 0) { m_DataEvent.Reset(); - m_expectingInput = false; - m_expectingCommand = false; + m_expectingInput = false; + m_expectingCommand = false; return ""; } @@ -278,19 +278,19 @@ namespace OpenSim.Framework.Console } - m_expectingInput = false; - m_expectingCommand = false; + m_expectingInput = false; + m_expectingCommand = false; - // Echo to all the other users what we have done. This - // will also go to ourselves. - Output (cmdinput, String.Empty, false, false, true); + // Echo to all the other users what we have done. This + // will also go to ourselves. + Output (cmdinput, String.Empty, false, false, true); - // If this is a command, we need to resolve and execute it. + // If this is a command, we need to resolve and execute it. if (isCommand) { - // This call will actually execute the command and create - // any output associated with it. The core just gets an - // empty string so it will call again immediately. + // This call will actually execute the command and create + // any output associated with it. The core just gets an + // empty string so it will call again immediately. string[] cmd = Commands.Resolve(Parser.Parse(cmdinput)); if (cmd.Length != 0) @@ -306,11 +306,11 @@ namespace OpenSim.Framework.Console } } - // Return the raw input string if not a command. + // Return the raw input string if not a command. return cmdinput; } - // Very simplistic static access control header. + // Very simplistic static access control header. protected Hashtable CheckOrigin(Hashtable result) { if (!string.IsNullOrEmpty(m_AllowedOrigin)) @@ -338,21 +338,21 @@ namespace OpenSim.Framework.Console protected void DoExpire(Object sender, ElapsedEventArgs e) { - // Iterate the list of console connections and find those we - // haven't heard from for longer then the longpoll interval. - // Remove them. + // Iterate the list of console connections and find those we + // haven't heard from for longer then the longpoll interval. + // Remove them. List expired = new List(); lock (m_Connections) { - // Mark the expired ones + // Mark the expired ones foreach (KeyValuePair kvp in m_Connections) { if (System.Environment.TickCount - kvp.Value.last > 500000) expired.Add(kvp.Key); } - // Delete them + // Delete them foreach (UUID id in expired) { m_Connections.Remove(id); @@ -361,10 +361,10 @@ namespace OpenSim.Framework.Console } } - // Start a new session. + // Start a new session. protected Hashtable HandleHttpStartSession(Hashtable request) { - // The login is in the form of a http form post + // The login is in the form of a http form post Hashtable post = DecodePostString(request["body"].ToString()); Hashtable reply = new Hashtable(); @@ -372,7 +372,7 @@ namespace OpenSim.Framework.Console reply["int_response_code"] = 401; reply["content_type"] = "text/plain"; - // Check user name and password + // Check user name and password if (m_UserName == String.Empty) return reply; @@ -385,28 +385,28 @@ namespace OpenSim.Framework.Console return reply; } - // Set up the new console connection record + // Set up the new console connection record ConsoleConnection c = new ConsoleConnection(); c.last = System.Environment.TickCount; c.lastLineSeen = 0; - // Assign session ID + // Assign session ID UUID sessionID = UUID.Random(); - // Add connection to list. + // Add connection to list. lock (m_Connections) { m_Connections[sessionID] = c; } - // This call is a CAP. The URL is the authentication. + // This call is a CAP. The URL is the authentication. string uri = "/ReadResponses/" + sessionID.ToString() + "/"; m_Server.AddPollServiceHTTPHandler( uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout - // Our reply is an XML document. - // TODO: Change this to Linq.Xml + // Our reply is an XML document. + // TODO: Change this to Linq.Xml XmlDocument xmldoc = new XmlDocument(); XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, "", ""); @@ -429,7 +429,7 @@ namespace OpenSim.Framework.Console rootElement.AppendChild(MainConsole.Instance.Commands.GetXml(xmldoc)); - // Set up the response and check origin + // Set up the response and check origin reply["str_response_string"] = xmldoc.InnerXml; reply["int_response_code"] = 200; reply["content_type"] = "text/xml"; @@ -438,7 +438,7 @@ namespace OpenSim.Framework.Console return reply; } - // Client closes session. Clean up. + // Client closes session. Clean up. protected Hashtable HandleHttpCloseSession(Hashtable request) { Hashtable post = DecodePostString(request["body"].ToString()); @@ -487,7 +487,7 @@ namespace OpenSim.Framework.Console return reply; } - // Command received from the client. + // Command received from the client. protected Hashtable HandleHttpSessionCommand(Hashtable request) { Hashtable post = DecodePostString(request["body"].ToString()); @@ -497,7 +497,7 @@ namespace OpenSim.Framework.Console reply["int_response_code"] = 404; reply["content_type"] = "text/plain"; - // Check the ID + // Check the ID if (post["ID"] == null) return reply; @@ -505,25 +505,25 @@ namespace OpenSim.Framework.Console if (!UUID.TryParse(post["ID"].ToString(), out id)) return reply; - // Find the connection for that ID. + // Find the connection for that ID. lock (m_Connections) { if (!m_Connections.ContainsKey(id)) return reply; } - // Empty post. Just error out. + // Empty post. Just error out. if (post["COMMAND"] == null) return reply; - // Place the input data in the buffer. + // Place the input data in the buffer. lock (m_InputData) { m_DataEvent.Set(); m_InputData.Add(post["COMMAND"].ToString()); } - // Create the XML reply document. + // Create the XML reply document. XmlDocument xmldoc = new XmlDocument(); XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, "", ""); @@ -547,7 +547,7 @@ namespace OpenSim.Framework.Console return reply; } - // Decode a HTTP form post to a Hashtable + // Decode a HTTP form post to a Hashtable protected Hashtable DecodePostString(string data) { Hashtable result = new Hashtable(); @@ -565,14 +565,14 @@ namespace OpenSim.Framework.Console if (elems.Length > 1) value = System.Web.HttpUtility.UrlDecode(elems[1]); - + result[name] = value; } return result; } - // Close the CAP receiver for the responses for a given client. + // Close the CAP receiver for the responses for a given client. public void CloseConnection(UUID id) { try @@ -586,8 +586,8 @@ namespace OpenSim.Framework.Console } } - // Check if there is anything to send. Return true if this client has - // lines pending. + // Check if there is anything to send. Return true if this client has + // lines pending. protected bool HasEvents(UUID RequestID, UUID sessionID) { ConsoleConnection c = null; @@ -604,10 +604,10 @@ namespace OpenSim.Framework.Console return false; } - // Send all pending output to the client. + // Send all pending output to the client. protected Hashtable GetEvents(UUID RequestID, UUID sessionID) { - // Find the connection that goes with this client. + // Find the connection that goes with this client. ConsoleConnection c = null; lock (m_Connections) @@ -617,14 +617,14 @@ namespace OpenSim.Framework.Console c = m_Connections[sessionID]; } - // If we have nothing to send, send the no events response. + // If we have nothing to send, send the no events response. c.last = System.Environment.TickCount; if (c.lastLineSeen >= m_lineNumber) return NoEvents(RequestID, UUID.Zero); Hashtable result = new Hashtable(); - // Create the response document. + // Create the response document. XmlDocument xmldoc = new XmlDocument(); XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, "", ""); @@ -648,29 +648,29 @@ namespace OpenSim.Framework.Console for (long i = sendStart ; i < m_lineNumber ; i++) { - ScrollbackEntry e = m_Scrollback[(int)(i - startLine)]; + ScrollbackEntry e = m_Scrollback[(int)(i - startLine)]; XmlElement res = xmldoc.CreateElement("", "Line", ""); res.SetAttribute("Number", e.lineNumber.ToString()); res.SetAttribute("Level", e.level); - // Don't include these for the scrollback, we'll send the - // real state later. - if (!c.newConnection) - { - res.SetAttribute("Prompt", e.isPrompt ? "true" : "false"); - res.SetAttribute("Command", e.isCommand ? "true" : "false"); - res.SetAttribute("Input", e.isInput ? "true" : "false"); - } - else if (i == m_lineNumber - 1) // Last line for a new connection - { - res.SetAttribute("Prompt", m_expectingInput ? "true" : "false"); - res.SetAttribute("Command", m_expectingCommand ? "true" : "false"); - res.SetAttribute("Input", (!m_expectingInput) ? "true" : "false"); - } - else - { - res.SetAttribute("Input", e.isInput ? "true" : "false"); - } + // Don't include these for the scrollback, we'll send the + // real state later. + if (!c.newConnection) + { + res.SetAttribute("Prompt", e.isPrompt ? "true" : "false"); + res.SetAttribute("Command", e.isCommand ? "true" : "false"); + res.SetAttribute("Input", e.isInput ? "true" : "false"); + } + else if (i == m_lineNumber - 1) // Last line for a new connection + { + res.SetAttribute("Prompt", m_expectingInput ? "true" : "false"); + res.SetAttribute("Command", m_expectingCommand ? "true" : "false"); + res.SetAttribute("Input", (!m_expectingInput) ? "true" : "false"); + } + else + { + res.SetAttribute("Input", e.isInput ? "true" : "false"); + } res.AppendChild(xmldoc.CreateTextNode(e.text)); @@ -679,7 +679,7 @@ namespace OpenSim.Framework.Console } c.lastLineSeen = m_lineNumber; - c.newConnection = false; + c.newConnection = false; xmldoc.AppendChild(rootElement); @@ -693,8 +693,8 @@ namespace OpenSim.Framework.Console return result; } - // This is really just a no-op. It generates what is sent - // to the client if the poll times out without any events. + // This is really just a no-op. It generates what is sent + // to the client if the poll times out without any events. protected Hashtable NoEvents(UUID RequestID, UUID id) { Hashtable result = new Hashtable(); diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs index 4995a92de0..1915fa52f9 100644 --- a/OpenSim/Framework/DAMap.cs +++ b/OpenSim/Framework/DAMap.cs @@ -63,9 +63,9 @@ namespace OpenSim.Framework { get { return m_map; } set { m_map = value; } - } - - public XmlSchema GetSchema() { return null; } + } + + public XmlSchema GetSchema() { return null; } public static DAMap FromXml(string rawXml) { @@ -73,19 +73,19 @@ namespace OpenSim.Framework map.ReadXml(rawXml); return map; } - + public void ReadXml(XmlReader reader) - { - ReadXml(reader.ReadInnerXml()); + { + ReadXml(reader.ReadInnerXml()); } public void ReadXml(string rawXml) - { + { // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml); - + lock (this) { - m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml); + m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml); SanitiseMap(this); } } @@ -104,7 +104,7 @@ namespace OpenSim.Framework public void CopyFrom(DAMap other) { // Deep copy - + string data = null; lock (other) { @@ -113,7 +113,7 @@ namespace OpenSim.Framework data = OSDParser.SerializeLLSDXmlString(other.m_map); } } - + lock (this) { if (data == null) @@ -185,9 +185,9 @@ namespace OpenSim.Framework /// /// Get the number of stores. /// - public int CountStores + public int CountStores { - get + get { int count = 0; @@ -263,8 +263,8 @@ namespace OpenSim.Framework throw new Exception("Minimum namespace length is " + MIN_NAMESPACE_LENGTH); } - public bool ContainsStore(string ns, string storeName) - { + public bool ContainsStore(string ns, string storeName) + { OSD namespaceOsd; lock (this) @@ -276,7 +276,7 @@ namespace OpenSim.Framework } return false; - } + } public bool TryGetStore(string ns, string storeName, out OSDMap store) { @@ -297,17 +297,17 @@ namespace OpenSim.Framework store = null; return false; - } + } public void Clear() { lock (this) m_map.Clear(); - } + } public bool RemoveStore(string ns, string storeName) { - OSD namespaceOsd; + OSD namespaceOsd; lock (this) { @@ -323,6 +323,6 @@ namespace OpenSim.Framework } return false; - } + } } } \ No newline at end of file diff --git a/OpenSim/Framework/DOMap.cs b/OpenSim/Framework/DOMap.cs index f5b650b375..033cbf9723 100644 --- a/OpenSim/Framework/DOMap.cs +++ b/OpenSim/Framework/DOMap.cs @@ -47,7 +47,7 @@ namespace OpenSim.Framework public class DOMap { private IDictionary m_map; - + public void Add(string ns, string objName, object dynObj) { DAMap.ValidateNamespace(ns); diff --git a/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs index 4ff8cbabfa..55ec13e5d3 100644 --- a/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs +++ b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs @@ -69,7 +69,7 @@ namespace OpenSim.Framework // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterWriteLock(); @@ -90,10 +90,10 @@ namespace OpenSim.Framework Dictionary1[key1] = value; Dictionary2[key2] = value; } - finally - { + finally + { if (gotLock) - rwLock.ExitWriteLock(); + rwLock.ExitWriteLock(); } } @@ -107,7 +107,7 @@ namespace OpenSim.Framework // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterWriteLock(); @@ -117,10 +117,10 @@ namespace OpenSim.Framework Dictionary1.Remove(key1); success = Dictionary2.Remove(key2); } - finally - { + finally + { if (gotLock) - rwLock.ExitWriteLock(); + rwLock.ExitWriteLock(); } return success; @@ -136,7 +136,7 @@ namespace OpenSim.Framework // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterWriteLock(); @@ -159,10 +159,10 @@ namespace OpenSim.Framework } } } - finally - { + finally + { if (gotLock) - rwLock.ExitWriteLock(); + rwLock.ExitWriteLock(); } return found; @@ -178,7 +178,7 @@ namespace OpenSim.Framework // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterWriteLock(); @@ -201,10 +201,10 @@ namespace OpenSim.Framework } } } - finally - { + finally + { if (gotLock) - rwLock.ExitWriteLock(); + rwLock.ExitWriteLock(); } return found; @@ -219,7 +219,7 @@ namespace OpenSim.Framework // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterWriteLock(); @@ -229,10 +229,10 @@ namespace OpenSim.Framework Dictionary1.Clear(); Dictionary2.Clear(); } - finally - { + finally + { if (gotLock) - rwLock.ExitWriteLock(); + rwLock.ExitWriteLock(); } } @@ -256,24 +256,24 @@ namespace OpenSim.Framework bool success; bool gotLock = false; - try - { + try + { // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterReadLock(); gotLock = true; } - success = Dictionary1.TryGetValue(key, out value); + success = Dictionary1.TryGetValue(key, out value); } - finally - { + finally + { if (gotLock) - rwLock.ExitReadLock(); + rwLock.ExitReadLock(); } return success; @@ -284,24 +284,24 @@ namespace OpenSim.Framework bool success; bool gotLock = false; - try - { + try + { // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterReadLock(); gotLock = true; } - success = Dictionary2.TryGetValue(key, out value); + success = Dictionary2.TryGetValue(key, out value); } - finally - { + finally + { if (gotLock) - rwLock.ExitReadLock(); + rwLock.ExitReadLock(); } return success; @@ -316,7 +316,7 @@ namespace OpenSim.Framework // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterReadLock(); @@ -326,10 +326,10 @@ namespace OpenSim.Framework foreach (TValue value in Dictionary1.Values) action(value); } - finally - { + finally + { if (gotLock) - rwLock.ExitReadLock(); + rwLock.ExitReadLock(); } } @@ -342,7 +342,7 @@ namespace OpenSim.Framework // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterReadLock(); @@ -352,10 +352,10 @@ namespace OpenSim.Framework foreach (KeyValuePair entry in Dictionary1) action(entry); } - finally - { + finally + { if (gotLock) - rwLock.ExitReadLock(); + rwLock.ExitReadLock(); } } @@ -368,7 +368,7 @@ namespace OpenSim.Framework // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterReadLock(); @@ -378,10 +378,10 @@ namespace OpenSim.Framework foreach (KeyValuePair entry in Dictionary2) action(entry); } - finally - { + finally + { if (gotLock) - rwLock.ExitReadLock(); + rwLock.ExitReadLock(); } } @@ -394,7 +394,7 @@ namespace OpenSim.Framework // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterReadLock(); @@ -407,10 +407,10 @@ namespace OpenSim.Framework return value; } } - finally - { + finally + { if (gotLock) - rwLock.ExitReadLock(); + rwLock.ExitReadLock(); } return default(TValue); @@ -426,7 +426,7 @@ namespace OpenSim.Framework // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterReadLock(); @@ -439,10 +439,10 @@ namespace OpenSim.Framework list.Add(value); } } - finally - { + finally + { if (gotLock) - rwLock.ExitReadLock(); + rwLock.ExitReadLock(); } return list; @@ -458,7 +458,7 @@ namespace OpenSim.Framework // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing // the acquision inside the main try. The inner finally block is needed because thread aborts cannot // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly). - try {} + try {} finally { rwLock.EnterUpgradeableReadLock(); @@ -482,7 +482,7 @@ namespace OpenSim.Framework try { - try {} + try {} finally { rwLock.EnterUpgradeableReadLock(); @@ -495,16 +495,16 @@ namespace OpenSim.Framework for (int i = 0; i < list2.Count; i++) Dictionary2.Remove(list2[i]); } - finally - { + finally + { if (gotWriteLock) - rwLock.ExitWriteLock(); + rwLock.ExitWriteLock(); } } - finally - { + finally + { if (gotUpgradeableLock) - rwLock.ExitUpgradeableReadLock(); + rwLock.ExitUpgradeableReadLock(); } return list.Count; diff --git a/OpenSim/Framework/EstateBan.cs b/OpenSim/Framework/EstateBan.cs index ebed794619..12a92bb0e2 100644 --- a/OpenSim/Framework/EstateBan.cs +++ b/OpenSim/Framework/EstateBan.cs @@ -43,7 +43,7 @@ namespace OpenSim.Framework { get { - return m_estateID; + return m_estateID; } set { diff --git a/OpenSim/Framework/EstateSettings.cs b/OpenSim/Framework/EstateSettings.cs index 844230b278..7134cbf825 100644 --- a/OpenSim/Framework/EstateSettings.cs +++ b/OpenSim/Framework/EstateSettings.cs @@ -430,7 +430,7 @@ namespace OpenSim.Framework { if (ban == null) return; - if (!IsBanned(ban.BannedUserID, 32) && + if (!IsBanned(ban.BannedUserID, 32) && (l_EstateBans.Count < (int)Constants.EstateAccessLimits.EstateBans)) //Ignore age-based bans l_EstateBans.Add(ban); } diff --git a/OpenSim/Framework/GridInstantMessage.cs b/OpenSim/Framework/GridInstantMessage.cs index 6954c64e20..1605005a8a 100644 --- a/OpenSim/Framework/GridInstantMessage.cs +++ b/OpenSim/Framework/GridInstantMessage.cs @@ -67,7 +67,7 @@ namespace OpenSim.Framework binaryBucket = im.binaryBucket; RegionID = im.RegionID; ParentEstateID = im.ParentEstateID; - + if (addTimestamp) timestamp = (uint)Util.UnixTimeSinceEpoch(); } diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 1541b3a3dc..1267993d1f 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -60,7 +60,7 @@ namespace OpenSim.Framework public delegate void ObjectAttach( IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent); - public delegate void ModifyTerrain(UUID user, + public delegate void ModifyTerrain(UUID user, float height, float seconds, byte size, byte action, float north, float west, float south, float east, UUID agentId); @@ -473,46 +473,46 @@ namespace OpenSim.Framework public delegate void PlacesQuery(UUID QueryID, UUID TransactionID, string QueryText, uint QueryFlags, byte Category, string SimName, IClientAPI client); public delegate void AgentFOV(IClientAPI client, float verticalAngle); - + public delegate void MuteListEntryUpdate(IClientAPI client, UUID MuteID, string Name, int type, uint flags); - + public delegate void MuteListEntryRemove(IClientAPI client, UUID MuteID, string Name); - + public delegate void AvatarInterestReply(IClientAPI client,UUID target, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages); - + public delegate void FindAgentUpdate(IClientAPI client, UUID hunter, UUID target); - + public delegate void TrackAgentUpdate(IClientAPI client, UUID hunter, UUID target); - + public delegate void FreezeUserUpdate(IClientAPI client, UUID parcelowner,uint flags, UUID target); - + public delegate void EjectUserUpdate(IClientAPI client, UUID parcelowner,uint flags, UUID target); - + public delegate void NewUserReport(IClientAPI client, string regionName,UUID abuserID, byte catagory, byte checkflags, string details, UUID objectID, Vector3 postion, byte reportType ,UUID screenshotID, string Summary, UUID reporter); - + public delegate void GodUpdateRegionInfoUpdate(IClientAPI client, float BillableFactor, ulong EstateID, ulong RegionFlags, byte[] SimName,int RedirectX, int RedirectY); - + public delegate void GodlikeMessage(IClientAPI client, UUID requester, byte[] Method, byte[] Parameter); - + public delegate void SaveStateHandler(IClientAPI client,UUID agentID); - + public delegate void GroupAccountSummaryRequest(IClientAPI client,UUID agentID, UUID groupID); - + public delegate void GroupAccountDetailsRequest(IClientAPI client,UUID agentID, UUID groupID, UUID transactionID, UUID sessionID); - + public delegate void GroupAccountTransactionsRequest(IClientAPI client,UUID agentID, UUID groupID, UUID transactionID, UUID sessionID); - + public delegate void ParcelBuyPass(IClientAPI client, UUID agentID, int ParcelLocalID); - + public delegate void ParcelGodMark(IClientAPI client, UUID agentID, int ParcelLocalID); - + public delegate void GroupActiveProposalsRequest(IClientAPI client,UUID agentID, UUID groupID, UUID transactionID, UUID sessionID); - + public delegate void GroupVoteHistoryRequest(IClientAPI client,UUID agentID, UUID groupID, UUID transactionID, UUID sessionID); - - + + public delegate void SimWideDeletesDelegate(IClientAPI client,UUID agentID, int flags, UUID targetID); - + public delegate void SendPostcard(IClientAPI client); public delegate void ChangeInventoryItemFlags(IClientAPI client, UUID itemID, uint flags); @@ -763,7 +763,7 @@ namespace OpenSim.Framework /// Only set for root agents. /// bool IsLoggingOut { get; set; } - + bool SendLogoutPacketWhenClosing { set; } // [Obsolete("LLClientView Specific - Circuits are unique to LLClientView")] @@ -1034,7 +1034,7 @@ namespace OpenSim.Framework event MuteListRequest OnMuteListRequest; event PlacesQuery OnPlacesQuery; - + event FindAgentUpdate OnFindAgent; event TrackAgentUpdate OnTrackAgent; event NewUserReport OnUserReport; @@ -1079,12 +1079,12 @@ namespace OpenSim.Framework void Close(bool sendStop, bool force); void Kick(string message); - + /// /// Start processing for this client. /// void Start(); - + void Stop(); // void ActivateGesture(UUID assetId, UUID gestureId); @@ -1155,7 +1155,7 @@ namespace OpenSim.Framework void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look); void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint); - + /// /// Return circuit information for this client. /// @@ -1223,10 +1223,10 @@ namespace OpenSim.Framework /// /// Used by the server to inform the client of new inventory items and folders. /// - /// + /// /// If the node is a folder then the contents will be transferred /// (including all descendent folders) as well as the folder itself. - /// + /// /// void SendBulkUpdateInventory(InventoryNodeBase node); @@ -1289,7 +1289,7 @@ namespace OpenSim.Framework /// The orbital position is given in radians, and must be "adjusted" for the linden client, see LLClientView void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong CurrentTime, uint SecondsPerSunCycle, uint SecondsPerYear, float OrbitalPosition); - + void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks); void SendViewerTime(int phase); @@ -1357,7 +1357,7 @@ namespace OpenSim.Framework void SendImageFirstPart(ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec); /// - /// Send the next packet for a series of packets making up a single texture, + /// Send the next packet for a series of packets making up a single texture, /// as established by SendImageFirstPart() /// /// @@ -1481,7 +1481,7 @@ namespace OpenSim.Framework void SendParcelDwellReply(int localID, UUID parcelID, float dwell); void SendUserInfoReply(bool imViaEmail, bool visible, string email); - + void SendUseCachedMuteList(); void SendMuteListUpdate(string filename); @@ -1495,13 +1495,13 @@ namespace OpenSim.Framework void SendRebakeAvatarTextures(UUID textureID); void SendAvatarInterestsReply(UUID avatarID, uint wantMask, string wantText, uint skillsMask, string skillsText, string languages); - + void SendGroupAccountingDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt); - + void SendGroupAccountingSummary(IClientAPI sender,UUID groupID, uint moneyAmt, int totalTier, int usedTier); - + void SendGroupTransactionsSummaryDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID,int amt); - + void SendChangeUserRights(UUID agentID, UUID friendID, int rights); void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId); diff --git a/OpenSim/Framework/ICnmCache.cs b/OpenSim/Framework/ICnmCache.cs index 27b9c56318..69b5b423e5 100644 --- a/OpenSim/Framework/ICnmCache.cs +++ b/OpenSim/Framework/ICnmCache.cs @@ -34,10 +34,10 @@ namespace OpenSim.Framework /// Represent generic cache to store key/value pairs (elements) limited by time, size and count of elements. /// /// - /// The type of keys in the cache. + /// The type of keys in the cache. /// /// - /// The type of values in the cache. + /// The type of values in the cache. /// /// /// @@ -51,8 +51,8 @@ namespace OpenSim.Framework /// /// Time /// - /// Element that is not accessed through or in last are - /// removed from the cache automatically. Depending on implementation of the cache some of elements may stay longer in cache. + /// Element that is not accessed through or in last are + /// removed from the cache automatically. Depending on implementation of the cache some of elements may stay longer in cache. /// returns , if cache is limited by time. /// /// @@ -60,7 +60,7 @@ namespace OpenSim.Framework /// Count /// /// When adding an new element to cache that already have of elements, cache will remove less recently - /// used element(s) from the cache, until element fits to cache. + /// used element(s) from the cache, until element fits to cache. /// returns , if cache is limiting element count. /// /// @@ -69,8 +69,8 @@ namespace OpenSim.Framework /// /// /// When adding an new element to cache that already have of elements, cache will remove less recently - /// used element(s) from the cache, until element fits to cache. - /// returns , if cache is limiting total size of elements. + /// used element(s) from the cache, until element fits to cache. + /// returns , if cache is limiting total size of elements. /// Normally size is bytes used by element in the cache. But it can be any other suitable unit of measure. /// /// @@ -84,8 +84,8 @@ namespace OpenSim.Framework /// /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -102,13 +102,13 @@ namespace OpenSim.Framework /// /// /// - /// When element has been stored in longer than - /// and it is not accessed through method or element's value is - /// not replaced by method, then it is automatically removed from the + /// When element has been stored in longer than + /// and it is not accessed through method or element's value is + /// not replaced by method, then it is automatically removed from the /// . /// /// - /// It is possible that implementation removes element before it's expiration time, + /// It is possible that implementation removes element before it's expiration time, /// because total size or count of elements stored to cache is larger than or . /// /// @@ -135,12 +135,12 @@ namespace OpenSim.Framework /// Gets a value indicating whether or not access to the is synchronized (thread safe). /// /// - /// if access to the is synchronized (thread safe); - /// otherwise, . + /// if access to the is synchronized (thread safe); + /// otherwise, . /// /// /// - /// To get synchronized (thread safe) access to object, use + /// To get synchronized (thread safe) access to object, use /// in class /// to retrieve synchronized wrapper for object. /// @@ -153,17 +153,17 @@ namespace OpenSim.Framework /// Gets a value indicating whether is limiting count of elements. /// /// - /// if the count of elements is limited; - /// otherwise, . + /// if the count of elements is limited; + /// otherwise, . /// /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// /// - /// + /// /// /// bool IsCountLimited { get; } @@ -172,13 +172,13 @@ namespace OpenSim.Framework /// Gets a value indicating whether is limiting size of elements. /// /// - /// if the total size of elements is limited; - /// otherwise, . + /// if the total size of elements is limited; + /// otherwise, . /// /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -192,13 +192,13 @@ namespace OpenSim.Framework /// Gets a value indicating whether elements stored to have limited inactivity time. /// /// - /// if the has a fixed total size of elements; - /// otherwise, . + /// if the has a fixed total size of elements; + /// otherwise, . /// /// /// If have limited inactivity time and element is not accessed through - /// or methods in , then element is automatically removed from - /// the cache. Depending on implementation of the , some of the elements may + /// or methods in , then element is automatically removed from + /// the cache. Depending on implementation of the , some of the elements may /// stay longer in cache. /// /// @@ -206,18 +206,18 @@ namespace OpenSim.Framework /// /// bool IsTimeLimited { get; } - + /// /// Gets or sets maximal allowed count of elements that can be stored to . /// /// - /// , if is not limited by count of elements; + /// , if is not limited by count of elements; /// otherwise maximal allowed count of elements. /// /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// int MaxCount { get; set; } @@ -230,7 +230,7 @@ namespace OpenSim.Framework /// /// /// - /// If element's size is larger than , then element is + /// If element's size is larger than , then element is /// not added to the . /// /// @@ -251,8 +251,8 @@ namespace OpenSim.Framework /// Normally size is total bytes used by elements in the cache. But it can be any other suitable unit of measure. /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// /// value is less than 0. @@ -272,11 +272,11 @@ namespace OpenSim.Framework /// Normally bytes, but can be any suitable unit of measure. /// /// - /// Element's size is given when element is added or replaced by method. + /// Element's size is given when element is added or replaced by method. /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -294,8 +294,8 @@ namespace OpenSim.Framework /// /// /// - /// To get synchronized (thread safe) access to , use - /// method to retrieve synchronized wrapper interface to + /// To get synchronized (thread safe) access to , use + /// method to retrieve synchronized wrapper interface to /// . /// /// @@ -367,7 +367,7 @@ namespace OpenSim.Framework void RemoveRange(IEnumerable keys); /// - /// Add or replace an element with the provided , and to + /// Add or replace an element with the provided , and to /// . /// /// @@ -380,7 +380,7 @@ namespace OpenSim.Framework /// The element's size. Normally bytes, but can be any suitable unit of measure. /// /// - /// if element has been added successfully to the ; + /// if element has been added successfully to the ; /// otherwise . /// /// @@ -391,17 +391,17 @@ namespace OpenSim.Framework /// /// /// - /// If element's is larger than , then element is - /// not added to the , however - possible older element is - /// removed from the . + /// If element's is larger than , then element is + /// not added to the , however - possible older element is + /// removed from the . /// /// - /// When adding an new element to that is limiting total size of elements, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. /// /// - /// When adding an new element to that is limiting element count, - /// will remove less recently used elements until it can fit an new element. + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. /// /// /// @@ -417,15 +417,15 @@ namespace OpenSim.Framework /// Gets the associated with the specified . /// /// - /// if the contains an element with + /// if the contains an element with /// the specified key; otherwise, . /// /// /// The key whose to get. /// /// - /// When this method returns, the value associated with the specified , - /// if the is found; otherwise, the + /// When this method returns, the value associated with the specified , + /// if the is found; otherwise, the /// default value for the type of the parameter. This parameter is passed uninitialized. /// /// diff --git a/OpenSim/Framework/ILandChannel.cs b/OpenSim/Framework/ILandChannel.cs index 63cc7ebf1e..44a24b94a3 100644 --- a/OpenSim/Framework/ILandChannel.cs +++ b/OpenSim/Framework/ILandChannel.cs @@ -38,7 +38,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// List AllParcels(); - + /// /// Get the parcel at the specified point /// @@ -75,7 +75,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// ILandObject GetLandObject(int localID); - + /// /// Clear the land channel of all parcels. /// @@ -83,7 +83,7 @@ namespace OpenSim.Region.Framework.Interfaces /// If true, set up a default parcel covering the whole region owned by the estate owner. /// void Clear(bool setupDefaultParcel); - + bool IsForcefulBansAllowed(); void UpdateLandObject(int localID, LandData data); void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient); diff --git a/OpenSim/Framework/ILandObject.cs b/OpenSim/Framework/ILandObject.cs index af072fe130..f3b850d528 100644 --- a/OpenSim/Framework/ILandObject.cs +++ b/OpenSim/Framework/ILandObject.cs @@ -43,33 +43,33 @@ namespace OpenSim.Framework LandData LandData { get; set; } bool[,] LandBitmap { get; set; } UUID RegionUUID { get; } - + /// /// Prim counts for this land object. /// IPrimCounts PrimCounts { get; set; } - + /// - /// The start point for the land object. This is the northern-most point as one scans land working from + /// The start point for the land object. This is the northern-most point as one scans land working from /// west to east. /// Vector2 StartPoint { get; } - + /// - /// The end point for the land object. This is the southern-most point as one scans land working from + /// The end point for the land object. This is the southern-most point as one scans land working from /// west to east. - /// + /// Vector2 EndPoint { get; } - // a estimation of a parcel center. + // a estimation of a parcel center. Vector2 CenterPoint { get; } - + // get positions Vector2? GetNearestPoint(Vector3 pos); Vector2? GetNearestPointAlongDirection(Vector3 pos, Vector3 pdirection); bool ContainsPoint(int x, int y); - + ILandObject Copy(); void SendLandUpdateToAvatarsOverMe(); @@ -97,16 +97,16 @@ namespace OpenSim.Framework /// /// The bitmap created. bool[,] BasicFullRegionLandBitmap(); - + /// /// Create a square land bitmap. /// /// /// Land co-ordinates are zero indexed. The inputs are treated as points. So if you want to create a bitmap - /// that covers an entire 256 x 256m region apart from a strip of land on the east, then you would need to + /// that covers an entire 256 x 256m region apart from a strip of land on the east, then you would need to /// specify start_x = 0, start_y = 0, end_x = 252 (or anything up to 255), end_y = 255. - /// - /// At the moment, the smallest parcel of land is 4m x 4m, so if the + /// + /// At the moment, the smallest parcel of land is 4m x 4m, so if the /// region is 256 x 256m (the SL size), the bitmap returned will start at (0,0) and end at (63,63). /// The value of the set_value needs to be true to define an active parcel of the given size. /// @@ -117,7 +117,7 @@ namespace OpenSim.Framework /// /// The bitmap created. bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y, bool set_value = true); - + bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, bool set_value); /// @@ -153,7 +153,7 @@ namespace OpenSim.Framework /// out: This is set if the resultant bitmap is now empty /// out: parcel.AABBMin <x,y,0> /// out: parcel.AABBMax <x,y,0> - /// New parcel bitmap + /// New parcel bitmap bool[,] RemoveFromLandBitmap(bool[,] bitmap_base, bool[,] bitmap_new, out bool isEmptyNow, out Vector3 AABBMin, out Vector3 AABBMax); byte[] ConvertLandBitmapToBytes(); @@ -177,7 +177,7 @@ namespace OpenSim.Framework /// /// void SetMediaUrl(string url); - + /// /// Set the music url for this land parcel /// diff --git a/OpenSim/Framework/IPrimCounts.cs b/OpenSim/Framework/IPrimCounts.cs index 3e12348e1b..3b62ad3118 100644 --- a/OpenSim/Framework/IPrimCounts.cs +++ b/OpenSim/Framework/IPrimCounts.cs @@ -35,12 +35,12 @@ namespace OpenSim.Framework /// Parcel owner owned prims /// int Owner { get; } - + /// /// Parcel group owned prims /// int Group { get; } - + /// /// Prims owned by others (not parcel owner or parcel group). /// @@ -48,19 +48,19 @@ namespace OpenSim.Framework /// /// Selected prims - /// - int Selected { get; } - + /// + int Selected { get; } + /// /// Total prims on the parcel. /// int Total { get; } - + /// /// Prims on the simulator that are owned by the parcel owner, even if they are in other parcels. /// int Simulator { get; } - + /// /// Prims per individual users. /// diff --git a/OpenSim/Framework/IRegistryCore.cs b/OpenSim/Framework/IRegistryCore.cs index a94b65d529..cf3ecc0a0a 100644 --- a/OpenSim/Framework/IRegistryCore.cs +++ b/OpenSim/Framework/IRegistryCore.cs @@ -31,7 +31,7 @@ using System.Text; namespace OpenSim.Framework { - public interface IRegistryCore + public interface IRegistryCore { T Get(); void RegisterInterface(T iface); diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs index e1b6d1e1ad..37a064fca6 100644 --- a/OpenSim/Framework/IScene.cs +++ b/OpenSim/Framework/IScene.cs @@ -40,7 +40,7 @@ namespace OpenSim.Framework Crashed = 2, Starting = 3, }; - + /// /// Indicate what action to take on an object derez request /// @@ -118,7 +118,7 @@ namespace OpenSim.Framework /// /// void RegisterModuleInterface(M mod); - + void StackModuleInterface(M mod); /// diff --git a/OpenSim/Framework/ISceneAgent.cs b/OpenSim/Framework/ISceneAgent.cs index c8424e3691..5534e24eaf 100644 --- a/OpenSim/Framework/ISceneAgent.cs +++ b/OpenSim/Framework/ISceneAgent.cs @@ -81,6 +81,6 @@ namespace OpenSim.Framework /// Direction in which the scene presence is looking. /// /// Will be Vector3.Zero for a child agent. - Vector3 Lookat { get; } + Vector3 Lookat { get; } } } \ No newline at end of file diff --git a/OpenSim/Framework/InventoryFolderImpl.cs b/OpenSim/Framework/InventoryFolderImpl.cs index 139776bb39..d14f3bee2b 100644 --- a/OpenSim/Framework/InventoryFolderImpl.cs +++ b/OpenSim/Framework/InventoryFolderImpl.cs @@ -314,7 +314,7 @@ namespace OpenSim.Framework /// XPath like expression /// /// FIXME: Delimitors which occur in names themselves are not currently escapable. - /// + /// /// /// The path to the required folder. /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. diff --git a/OpenSim/Framework/InventoryItemBase.cs b/OpenSim/Framework/InventoryItemBase.cs index f9fd752370..c359a0cca3 100644 --- a/OpenSim/Framework/InventoryItemBase.cs +++ b/OpenSim/Framework/InventoryItemBase.cs @@ -34,17 +34,17 @@ namespace OpenSim.Framework /// Inventory Item - contains all the properties associated with an individual inventory piece. /// public class InventoryItemBase : InventoryNodeBase, ICloneable - { + { /// /// The inventory type of the item. This is slightly different from the asset type in some situations. /// - public int InvType - { + public int InvType + { get { return m_invType; } - + set { m_invType = value; @@ -55,13 +55,13 @@ namespace OpenSim.Framework /// /// The folder this item is contained in /// - public UUID Folder - { + public UUID Folder + { get { return m_folder; } - + set { m_folder = value; @@ -72,17 +72,17 @@ namespace OpenSim.Framework /// /// The creator of this item /// - public string CreatorId - { + public string CreatorId + { get { - return m_creatorId; + return m_creatorId; } - + set { m_creatorId = value; - + if ((m_creatorId == null) || !UUID.TryParse(m_creatorId, out m_creatorIdAsUuid)) m_creatorIdAsUuid = UUID.Zero; } @@ -92,7 +92,7 @@ namespace OpenSim.Framework /// /// The CreatorId expressed as a UUID. /// - public UUID CreatorIdAsUuid + public UUID CreatorIdAsUuid { get { @@ -161,13 +161,13 @@ namespace OpenSim.Framework /// /// The description of the inventory item (must be less than 64 characters) /// - public string Description - { + public string Description + { get { return m_description; } - + set { m_description = value; @@ -178,13 +178,13 @@ namespace OpenSim.Framework /// /// /// - public uint NextPermissions - { + public uint NextPermissions + { get { return m_nextPermissions; } - + set { m_nextPermissions = value; @@ -195,13 +195,13 @@ namespace OpenSim.Framework /// /// A mask containing permissions for the current owner (cannot be enforced) /// - public uint CurrentPermissions - { + public uint CurrentPermissions + { get { return m_currentPermissions; } - + set { m_currentPermissions = value; @@ -212,13 +212,13 @@ namespace OpenSim.Framework /// /// /// - public uint BasePermissions - { + public uint BasePermissions + { get { return m_basePermissions; } - + set { m_basePermissions = value; @@ -229,13 +229,13 @@ namespace OpenSim.Framework /// /// /// - public uint EveryOnePermissions - { + public uint EveryOnePermissions + { get { return m_everyonePermissions; } - + set { m_everyonePermissions = value; @@ -246,13 +246,13 @@ namespace OpenSim.Framework /// /// /// - public uint GroupPermissions - { + public uint GroupPermissions + { get { return m_groupPermissions; } - + set { m_groupPermissions = value; @@ -263,13 +263,13 @@ namespace OpenSim.Framework /// /// This is an enumerated value determining the type of asset (eg Notecard, Sound, Object, etc) /// - public int AssetType - { + public int AssetType + { get { return m_assetType; } - + set { m_assetType = value; @@ -280,13 +280,13 @@ namespace OpenSim.Framework /// /// The UUID of the associated asset on the asset server /// - public UUID AssetID - { + public UUID AssetID + { get { return m_assetID; } - + set { m_assetID = value; @@ -297,13 +297,13 @@ namespace OpenSim.Framework /// /// /// - public UUID GroupID - { + public UUID GroupID + { get { return m_groupID; } - + set { m_groupID = value; @@ -314,13 +314,13 @@ namespace OpenSim.Framework /// /// /// - public bool GroupOwned - { + public bool GroupOwned + { get { return m_groupOwned; } - + set { m_groupOwned = value; @@ -331,13 +331,13 @@ namespace OpenSim.Framework /// /// /// - public int SalePrice - { + public int SalePrice + { get { return m_salePrice; } - + set { m_salePrice = value; @@ -348,13 +348,13 @@ namespace OpenSim.Framework /// /// /// - public byte SaleType - { + public byte SaleType + { get { return m_saleType; } - + set { m_saleType = value; @@ -365,13 +365,13 @@ namespace OpenSim.Framework /// /// /// - public uint Flags - { + public uint Flags + { get { return m_flags; } - + set { m_flags = value; @@ -382,13 +382,13 @@ namespace OpenSim.Framework /// /// /// - public int CreationDate - { + public int CreationDate + { get { return m_creationDate; } - + set { m_creationDate = value; diff --git a/OpenSim/Framework/InventoryNodeBase.cs b/OpenSim/Framework/InventoryNodeBase.cs index 31c3fd1840..9ef36b7bde 100644 --- a/OpenSim/Framework/InventoryNodeBase.cs +++ b/OpenSim/Framework/InventoryNodeBase.cs @@ -41,19 +41,19 @@ namespace OpenSim.Framework { get { return m_name; } set { m_name = value; } - } + } private string m_name = string.Empty; - + /// /// A UUID containing the ID for the inventory node itself /// - public UUID ID + public UUID ID { get { return m_id; } set { m_id = value; } } private UUID m_id; - + /// /// The agent who's inventory this is contained by /// diff --git a/OpenSim/Framework/LandData.cs b/OpenSim/Framework/LandData.cs index cfefe3e8e6..13d29776c5 100644 --- a/OpenSim/Framework/LandData.cs +++ b/OpenSim/Framework/LandData.cs @@ -411,7 +411,7 @@ namespace OpenSim.Framework } /// - /// Determines if people are able to teleport where they please on the parcel or if they + /// Determines if people are able to teleport where they please on the parcel or if they /// get constrainted to a specific point on teleport within the parcel /// public byte LandingType @@ -667,7 +667,7 @@ namespace OpenSim.Framework } /// - /// When teleporting is restricted to a certain point, this is the location + /// When teleporting is restricted to a certain point, this is the location /// that the user will be redirected to /// public Vector3 UserLocation @@ -683,7 +683,7 @@ namespace OpenSim.Framework } /// - /// When teleporting is restricted to a certain point, this is the rotation + /// When teleporting is restricted to a certain point, this is the rotation /// that the user will be positioned /// public Vector3 UserLookAt @@ -699,7 +699,7 @@ namespace OpenSim.Framework } /// - /// Autoreturn number of minutes to return SceneObjectGroup that are owned by someone who doesn't own + /// Autoreturn number of minutes to return SceneObjectGroup that are owned by someone who doesn't own /// the parcel and isn't set to the same 'group' as the parcel. /// public int OtherCleanTime diff --git a/OpenSim/Framework/Lazy.cs b/OpenSim/Framework/Lazy.cs index 91de4bdd1d..ea07d0ecf6 100644 --- a/OpenSim/Framework/Lazy.cs +++ b/OpenSim/Framework/Lazy.cs @@ -14,10 +14,10 @@ // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: -// +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/OpenSim/Framework/LocklessQueue.cs b/OpenSim/Framework/LocklessQueue.cs index 7ccbba7b55..21b81785c3 100644 --- a/OpenSim/Framework/LocklessQueue.cs +++ b/OpenSim/Framework/LocklessQueue.cs @@ -102,7 +102,7 @@ namespace OpenSim.Framework } else { - item = oldHeadNext.Item; + item = oldHeadNext.Item; haveAdvancedHead = CAS(ref head, oldHead, oldHeadNext); if (haveAdvancedHead) { diff --git a/OpenSim/Framework/MapAndArray.cs b/OpenSim/Framework/MapAndArray.cs index c98d3ccd6f..32d6978fb6 100644 --- a/OpenSim/Framework/MapAndArray.cs +++ b/OpenSim/Framework/MapAndArray.cs @@ -45,9 +45,9 @@ namespace OpenSim.Framework /// Number of values currently stored in the collection public int Count { get { return m_array.Length; } } - /// NOTE: This collection is thread safe. You do not need to - /// acquire a lock to add, remove, or enumerate entries. This - /// synchronization object should only be locked for larger + /// NOTE: This collection is thread safe. You do not need to + /// acquire a lock to add, remove, or enumerate entries. This + /// synchronization object should only be locked for larger /// transactions public object SyncRoot { get { return m_syncRoot; } } @@ -92,7 +92,7 @@ namespace OpenSim.Framework } /// - /// Adds a key/value pair to the collection. This will throw an + /// Adds a key/value pair to the collection. This will throw an /// exception if the key is already present in the collection /// /// Key to add or update @@ -166,7 +166,7 @@ namespace OpenSim.Framework /// Gets a reference to the immutable array of values stored in this /// collection. This array is thread safe for iteration /// - /// A thread safe reference ton an array of all of the stored + /// A thread safe reference ton an array of all of the stored /// values public TValue[] GetArray() { @@ -175,7 +175,7 @@ namespace OpenSim.Framework private void CreateArray() { - // Rebuild the array from the dictionary. This method must be + // Rebuild the array from the dictionary. This method must be // called from inside a lock TValue[] array = new TValue[m_dict.Count]; int i = 0; diff --git a/OpenSim/Framework/MapItemReplyStruct.cs b/OpenSim/Framework/MapItemReplyStruct.cs index c8693ae4d2..348a24079e 100644 --- a/OpenSim/Framework/MapItemReplyStruct.cs +++ b/OpenSim/Framework/MapItemReplyStruct.cs @@ -60,7 +60,7 @@ namespace OpenSim.Framework map["Extra2"] = OSD.FromInteger(Extra2); return map; } - + public void FromOSD(OSDMap map) { x = (uint) map["X"].AsInteger(); diff --git a/OpenSim/Framework/MetricsCollector.cs b/OpenSim/Framework/MetricsCollector.cs index c8f4a33260..391f57e4a7 100644 --- a/OpenSim/Framework/MetricsCollector.cs +++ b/OpenSim/Framework/MetricsCollector.cs @@ -42,23 +42,23 @@ namespace OpenSim.Framework } } - + struct MetricsBucket { public T value; public int count; } - + /// /// Collects metrics in a sliding window. /// /// /// MetricsCollector provides the current Sum of the metrics that it collects. It can easily be extended /// to provide the Average, too. It uses a sliding window to keep these values current. - /// + /// /// This class is not thread-safe. - /// + /// /// Subclass MetricsCollector to have it use a concrete value type. Override the abstract methods. /// public abstract class MetricsCollector diff --git a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs index 8c2bec6668..e513abd0f6 100644 --- a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs @@ -78,7 +78,7 @@ namespace OpenSim.Framework.Monitoring return sb.ToString(); } - + public virtual string XReport(string uptime, string version) { return (string) Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0).ToString() ; diff --git a/OpenSim/Framework/Monitoring/Checks/Check.cs b/OpenSim/Framework/Monitoring/Checks/Check.cs index 594386a93f..9a1bd4544a 100644 --- a/OpenSim/Framework/Monitoring/Checks/Check.cs +++ b/OpenSim/Framework/Monitoring/Checks/Check.cs @@ -79,7 +79,7 @@ namespace OpenSim.Framework.Monitoring string category, string container, Func checkFunc, - StatVerbosity verbosity) + StatVerbosity verbosity) { if (ChecksManager.SubCommands.Contains(category)) throw new Exception( @@ -108,9 +108,9 @@ namespace OpenSim.Framework.Monitoring public virtual string ToConsoleString() { return string.Format( - "{0}.{1}.{2} - {3}", - Category, - Container, + "{0}.{1}.{2} - {3}", + Category, + Container, ShortName, Description); } diff --git a/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs b/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs index 40df562a95..e326e8bff0 100644 --- a/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs @@ -39,7 +39,7 @@ namespace OpenSim.Framework.Monitoring /// /// string Report(); - + /// /// Report back collected statistical information in json /// diff --git a/OpenSim/Framework/Monitoring/JobEngine.cs b/OpenSim/Framework/Monitoring/JobEngine.cs index df6b806b4c..0a39e4b6be 100644 --- a/OpenSim/Framework/Monitoring/JobEngine.cs +++ b/OpenSim/Framework/Monitoring/JobEngine.cs @@ -49,7 +49,7 @@ namespace OpenSim.Framework.Monitoring /// /// Is this engine running? /// - public bool IsRunning { get; private set; } + public bool IsRunning { get; private set; } /// /// The current job that the engine is running. @@ -73,7 +73,7 @@ namespace OpenSim.Framework.Monitoring /// Controls whether we need to warn in the log about exceeding the max queue size. /// /// - /// This is flipped to false once queue max has been exceeded and back to true when it falls below max, in + /// This is flipped to false once queue max has been exceeded and back to true when it falls below max, in /// order to avoid spamming the log with lots of warnings. /// private bool m_warnOverMaxQueue = true; @@ -120,7 +120,7 @@ namespace OpenSim.Framework.Monitoring } public void Stop() - { + { lock (JobLock) { try @@ -150,7 +150,7 @@ namespace OpenSim.Framework.Monitoring /// Make a job. /// /// - /// We provide this method to replace the constructor so that we can later pool job objects if necessary to + /// We provide this method to replace the constructor so that we can later pool job objects if necessary to /// reduce memory churn. Normally one would directly call QueueJob() with parameters anyway. /// /// @@ -304,7 +304,7 @@ namespace OpenSim.Framework.Monitoring CommonId = commonId; Action = action; } - + /// /// Make a job. It needs to be separately queued. /// diff --git a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs index 756e4edd83..2ff2014b1a 100644 --- a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Framework.Monitoring")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,7 +25,7 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs index be4a8b463d..3391240ce5 100644 --- a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs @@ -167,18 +167,18 @@ namespace OpenSim.Framework.Monitoring } MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerThreadpool, - s => - { - int workerThreads, iocpThreads; - ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + s => + { + int workerThreads, iocpThreads; + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); s.Value = workerThreads; }); MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerThreadpool, - s => - { - int workerThreads, iocpThreads; - ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + s => + { + int workerThreads, iocpThreads; + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); s.Value = iocpThreads; }); @@ -193,10 +193,10 @@ namespace OpenSim.Framework.Monitoring } MakeStat( - "HTTPRequestsMade", - "Number of outbound HTTP requests made", - "requests", - ContainerNetwork, + "HTTPRequestsMade", + "Number of outbound HTTP requests made", + "requests", + ContainerNetwork, s => s.Value = WebUtil.RequestNumber, MeasuresOfInterest.AverageChangeOverTime); @@ -294,7 +294,7 @@ namespace OpenSim.Framework.Monitoring }); } - // Notes on performance counters: + // Notes on performance counters: // "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs index 08c24095be..88a02973fe 100755 --- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs @@ -90,17 +90,17 @@ namespace OpenSim.Framework.Monitoring // /// haven't yet been implemented... // /// // public long AssetsInCache { get { return assetsInCache; } } -// +// // /// // /// Currently unused // /// // public long TexturesInCache { get { return texturesInCache; } } -// +// // /// // /// Currently misleading since we can't currently subtract removed asset memory usage without a performance hit // /// // public long AssetCacheMemoryUsage { get { return assetCacheMemoryUsage; } } -// +// // /// // /// Currently unused // /// @@ -127,7 +127,7 @@ namespace OpenSim.Framework.Monitoring public float PendingUploads { get { return pendingUploads; } } public float ActiveScripts { get { return activeScripts; } } public float ScriptLinesPerSecond { get { return scriptLinesPerSecond; } } - + // /// // /// This is the time it took for the last asset request made in response to a cache miss. // /// @@ -177,7 +177,7 @@ namespace OpenSim.Framework.Monitoring // assetsInCache++; // //assetCacheMemoryUsage += asset.Data.Length; // } -// +// // public void RemoveAsset(UUID uuid) // { // assetsInCache--; @@ -204,7 +204,7 @@ namespace OpenSim.Framework.Monitoring // texturesInCache = 0; // textureCacheMemoryUsage = 0; // } -// +// // public void AddAssetRequestTimeAfterCacheMiss(TimeSpan ts) // { // assetRequestTimeAfterCacheMiss = ts; @@ -306,7 +306,7 @@ namespace OpenSim.Framework.Monitoring StringBuilder sb = new StringBuilder(Environment.NewLine); // sb.Append("ASSET STATISTICS"); // sb.Append(Environment.NewLine); - + /* sb.Append( string.Format( @@ -342,7 +342,7 @@ Asset service request failures: {3}" + Environment.NewLine, List stats = StatsManager.GetStatsFromEachContainer("clientstack", "ClientLogoutsDueToNoReceives"); sb.AppendFormat( - "Client logouts due to no data receive timeout: {0}\n\n", + "Client logouts due to no data receive timeout: {0}\n\n", stats != null ? stats.Sum(s => s.Value).ToString() : "unknown"); // sb.Append(Environment.NewLine); @@ -443,10 +443,10 @@ Asset service request failures: {3}" + Environment.NewLine, foreach (ProcessThread currentThread in Process.GetCurrentProcess().Threads) { - // A known issue with the current process .Threads property is - // that it can return null threads, thus don't count those as + // A known issue with the current process .Threads property is + // that it can return null threads, thus don't count those as // running threads and prevent the program function from failing - if (currentThread != null && + if (currentThread != null && currentThread.ThreadState == ThreadState.Running) { numberThreadsRunning++; @@ -505,7 +505,7 @@ Asset service request failures: {3}" + Environment.NewLine, "{0:0.##}", numberThreadsRunning)); args["ProcMem"] = OSD.FromString(String.Format("{0:#,###,###.##}", memUsage)); - + return args; } } @@ -531,12 +531,12 @@ Asset service request failures: {3}" + Environment.NewLine, { return m_statsProvider.GetStats(); } - + public string XReport(string uptime, string version) { return ""; } - + public OSDMap OReport(string uptime, string version) { OSDMap ret = new OSDMap(); diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index 916fa53908..2402acd2d1 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -121,17 +121,17 @@ namespace OpenSim.Framework.Monitoring string container, StatType type, Action pullAction, - StatVerbosity verbosity) + StatVerbosity verbosity) : this( - shortName, - name, - description, - unitName, - category, - container, - type, - MeasuresOfInterest.None, - pullAction, + shortName, + name, + description, + unitName, + category, + container, + type, + MeasuresOfInterest.None, + pullAction, verbosity) { } @@ -227,11 +227,11 @@ namespace OpenSim.Framework.Monitoring { StringBuilder sb = new StringBuilder(); sb.AppendFormat( - "{0}.{1}.{2} : {3}{4}", - Category, - Container, - ShortName, - Value, + "{0}.{1}.{2} : {3}{4}", + Category, + Container, + ShortName, + Value, string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName)); AppendMeasuresOfInterest(sb); @@ -290,7 +290,7 @@ namespace OpenSim.Framework.Monitoring lock (m_samples) { // m_log.DebugFormat( - // "[STAT]: Samples for {0} are {1}", + // "[STAT]: Samples for {0} are {1}", // Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray())); foreach (double s in m_samples) @@ -326,9 +326,9 @@ namespace OpenSim.Framework.Monitoring if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime)) { sb.AppendFormat( - ", {0:0.##}{1}/s, {2:0.##}{3}/s", - lastChangeOverTime, - string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName), + ", {0:0.##}{1}/s, {2:0.##}{3}/s", + lastChangeOverTime, + string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName), averageChangeOverTime, string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName)); } diff --git a/OpenSim/Framework/Monitoring/StatsLogger.cs b/OpenSim/Framework/Monitoring/StatsLogger.cs index 15a37aa104..b719af982e 100644 --- a/OpenSim/Framework/Monitoring/StatsLogger.cs +++ b/OpenSim/Framework/Monitoring/StatsLogger.cs @@ -99,13 +99,13 @@ namespace OpenSim.Framework.Monitoring } string path = cmd[2]; - + using (StreamWriter sw = new StreamWriter(path, true)) { foreach (string line in GetReport()) sw.WriteLine(line); - } - + } + MainConsole.Instance.OutputFormat("Stats saved to file {0}", path); } diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 30926d8e7d..55c327656a 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -274,7 +274,7 @@ namespace OpenSim.Framework.Monitoring { if (!(string.IsNullOrEmpty(pContainerName) || pContainerName == AllSubCommand || pContainerName == contName)) continue; - + OSDMap statMap = new OSDMap(); SortedDictionary theStats = RegisteredStats[catName][contName]; @@ -398,7 +398,7 @@ namespace OpenSim.Framework.Monitoring { if (!TryGetStatParents(stat, out category, out container)) return false; - + if(container != null) { container.Remove(stat.ShortName); diff --git a/OpenSim/Framework/Monitoring/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs index ff439f5c1f..9cc61ee62d 100644 --- a/OpenSim/Framework/Monitoring/Watchdog.cs +++ b/OpenSim/Framework/Monitoring/Watchdog.cs @@ -96,7 +96,7 @@ namespace OpenSim.Framework.Monitoring FirstTick = Environment.TickCount & Int32.MaxValue; LastTick = FirstTick; - Stat + Stat = new Stat( name, string.Format("Last update of thread {0}", name), diff --git a/OpenSim/Framework/Monitoring/WorkManager.cs b/OpenSim/Framework/Monitoring/WorkManager.cs index a7a03a0c13..43130f9a0b 100644 --- a/OpenSim/Framework/Monitoring/WorkManager.cs +++ b/OpenSim/Framework/Monitoring/WorkManager.cs @@ -36,16 +36,16 @@ namespace OpenSim.Framework.Monitoring /// Manages various work items in the simulator. /// /// - /// Currently, here work can be started + /// Currently, here work can be started /// * As a long-running and monitored thread. /// * In a thread that will never timeout but where the job is expected to eventually complete. /// * In a threadpool thread that will timeout if it takes a very long time to complete (> 10 mins). /// * As a job which will be run in a single-threaded job engine. Such jobs must not incorporate delays (sleeps, /// network waits, etc.). - /// + /// /// This is an evolving approach to better manage the work that OpenSimulator is asked to do from a very diverse /// range of sources (client actions, incoming network, outgoing network calls, etc.). - /// + /// /// Util.FireAndForget is still available to insert jobs in the threadpool, though this is equivalent to /// WorkManager.RunInThreadPool(). /// @@ -122,7 +122,7 @@ namespace OpenSim.Framework.Monitoring thread.Priority = priority; thread.IsBackground = isBackground; thread.Name = name; - + Watchdog.ThreadWatchdogInfo twi = new Watchdog.ThreadWatchdogInfo(thread, timeout, name) { AlarmIfTimeout = alarmIfTimeout, AlarmMethod = alarmMethod }; @@ -144,7 +144,7 @@ namespace OpenSim.Framework.Monitoring /// Name of the thread public static void RunInThread(WaitCallback callback, object obj, string name, bool log = false) { - if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest) + if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest) { Culture.SetCurrentCulture(); callback(obj); @@ -169,7 +169,7 @@ namespace OpenSim.Framework.Monitoring } /// - /// Run the callback via a threadpool thread. + /// Run the callback via a threadpool thread. /// /// /// Such jobs may run after some delay but must always complete. @@ -188,17 +188,17 @@ namespace OpenSim.Framework.Monitoring /// /// This differs from direct scheduling (e.g. Util.FireAndForget) in that a job can be run in the job /// engine if it is running, where all jobs are currently performed in sequence on a single thread. This is - /// to prevent observed overload and server freeze problems when there are hundreds of connections which all attempt to + /// to prevent observed overload and server freeze problems when there are hundreds of connections which all attempt to /// perform work at once (e.g. in conference situations). With lower numbers of connections, the small - /// delay in performing jobs in sequence rather than concurrently has not been notiecable in testing, though a future more + /// delay in performing jobs in sequence rather than concurrently has not been notiecable in testing, though a future more /// sophisticated implementation could perform jobs concurrently when the server is under low load. - /// + /// /// However, be advised that some callers of this function rely on all jobs being performed in sequence if any /// jobs are performed in sequence (i.e. if jobengine is active or not). Therefore, expanding the jobengine /// beyond a single thread will require considerable thought. - /// + /// /// Also, any jobs submitted must be guaranteed to complete within a reasonable timeframe (e.g. they cannot - /// incorporate a network delay with a long timeout). At the moment, work that could suffer such issues + /// incorporate a network delay with a long timeout). At the moment, work that could suffer such issues /// should still be run directly with RunInThread(), Util.FireAndForget(), etc. This is another area where /// the job engine could be improved and so CPU utilization improved by better management of concurrency within /// OpenSimulator. @@ -212,10 +212,10 @@ namespace OpenSim.Framework.Monitoring /// If set to true then extra logging is performed. public static void RunJob( string jobType, WaitCallback callback, object obj, string name, - bool canRunInThisThread = false, bool mustNotTimeout = false, + bool canRunInThisThread = false, bool mustNotTimeout = false, bool log = false) { - if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest) + if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest) { Culture.SetCurrentCulture(); callback(obj); @@ -273,16 +273,16 @@ namespace OpenSim.Framework.Monitoring MainConsole.Instance.Output("Usage: debug jobengine log "); return; } - + // int logLevel; int logLevel = int.Parse(args[3]); // if (ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out logLevel)) - // { + // { JobEngine.LogLevel = logLevel; MainConsole.Instance.OutputFormat("Set debug log level to {0}", JobEngine.LogLevel); // } } - else + else { MainConsole.Instance.OutputFormat("Unrecognized job engine subcommand {0}", subCommand); } diff --git a/OpenSim/Framework/NetworkUtil.cs b/OpenSim/Framework/NetworkUtil.cs index 2e94b0d5b4..93c94463a2 100644 --- a/OpenSim/Framework/NetworkUtil.cs +++ b/OpenSim/Framework/NetworkUtil.cs @@ -40,7 +40,7 @@ namespace OpenSim.Framework /// Handles NAT translation in a 'manner of speaking' /// Allows you to return multiple different external /// hostnames depending on the requestors network - /// + /// /// This enables standard port forwarding techniques /// to work correctly with OpenSim. /// @@ -145,7 +145,7 @@ namespace OpenSim.Framework byte[] subnetBytes = subnet.Value.GetAddressBytes(); byte[] localBytes = subnet.Key.GetAddressBytes(); byte[] destBytes = destination.GetAddressBytes(); - + if (subnetBytes.Length != destBytes.Length || subnetBytes.Length != localBytes.Length) return null; diff --git a/OpenSim/Framework/OutboundUrlFilter.cs b/OpenSim/Framework/OutboundUrlFilter.cs index baa3647677..ee4707fa8c 100644 --- a/OpenSim/Framework/OutboundUrlFilter.cs +++ b/OpenSim/Framework/OutboundUrlFilter.cs @@ -49,8 +49,8 @@ namespace OpenSim.Framework private List m_blacklistExceptionEndPoints; public OutboundUrlFilter( - string name, - List blacklistNetworks, List blacklistEndPoints, + string name, + List blacklistNetworks, List blacklistEndPoints, List blacklistExceptionNetworks, List blacklistExceptionEndPoints) { Name = name; @@ -79,7 +79,7 @@ namespace OpenSim.Framework if (networkConfig != null) { configBlacklist = networkConfig.GetString("OutboundDisallowForUserScripts", configBlacklist); - configBlacklistExceptions + configBlacklistExceptions = networkConfig.GetString("OutboundDisallowForUserScriptsExcept", configBlacklistExceptions); } @@ -98,7 +98,7 @@ namespace OpenSim.Framework string fullConfigEntry, string filterName, out List networks, out List endPoints) { // Parse blacklist - string[] configBlacklistEntries + string[] configBlacklistEntries = fullConfigEntry.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries); configBlacklistEntries = configBlacklistEntries.Select(e => e.Trim()).ToArray(); @@ -129,7 +129,7 @@ namespace OpenSim.Framework if (!Uri.TryCreate("http://" + configEntry, UriKind.Absolute, out configEntryUri)) { m_log.ErrorFormat( - "[OUTBOUND URL FILTER]: EndPoint entry [{0}] is invalid endpoint for {1}", + "[OUTBOUND URL FILTER]: EndPoint entry [{0}] is invalid endpoint for {1}", configEntry, filterName); continue; @@ -184,14 +184,14 @@ namespace OpenSim.Framework foreach (IPEndPoint ep in endPoints) { // m_log.DebugFormat( -// "[OUTBOUND URL FILTER]: Checking [{0}:{1}] against endpoint [{2}]", +// "[OUTBOUND URL FILTER]: Checking [{0}:{1}] against endpoint [{2}]", // addr, port, ep); if (addr.Equals(ep.Address) && port == ep.Port) { // m_log.DebugFormat( // "[OUTBOUND URL FILTER]: Found [{0}:{1}] in endpoint [{2}]", addr, port, ep); - + return true; } } @@ -228,7 +228,7 @@ namespace OpenSim.Framework // m_log.DebugFormat("[OUTBOUND URL FILTER]: Found [{0}] in blacklist for {1}", url, Name); // Check blacklist exceptions - allowed + allowed = OutboundUrlFilter.IsInNetwork( addr, url.Port, m_blacklistExceptionNetworks, m_blacklistExceptionEndPoints, Name); diff --git a/OpenSim/Framework/PluginManager.cs b/OpenSim/Framework/PluginManager.cs index 011709602b..0c94fcb32e 100644 --- a/OpenSim/Framework/PluginManager.cs +++ b/OpenSim/Framework/PluginManager.cs @@ -44,17 +44,17 @@ namespace OpenSim.Framework /// /// Manager for registries and plugins /// - public class PluginManager : SetupService - { - public AddinRegistry PluginRegistry; + public class PluginManager : SetupService + { + public AddinRegistry PluginRegistry; - public PluginManager(AddinRegistry registry): base (registry) + public PluginManager(AddinRegistry registry): base (registry) { - PluginRegistry = registry; + PluginRegistry = registry; - } + } - /// + /// /// Installs the plugin. /// /// @@ -97,14 +97,14 @@ namespace OpenSim.Framework Addin addin = PluginRegistry.GetAddin(aentry.Addin.Id); PluginRegistry.DisableAddin(addin.Id); addin.Enabled = false; - + MainConsole.Instance.Output("Installation Success"); ListInstalledAddins(out res); result = res; return true; - } + } else - { + { MainConsole.Instance.Output("Installation Failed"); result = res; return false; @@ -159,11 +159,11 @@ namespace OpenSim.Framework { Dictionary res = new Dictionary(); - Addin[] addins = GetSortedAddinList("RobustPlugin"); - if(addins.Count() < 1) - { - MainConsole.Instance.Output("Error!"); - } + Addin[] addins = GetSortedAddinList("RobustPlugin"); + if(addins.Count() < 1) + { + MainConsole.Instance.Output("Error!"); + } int count = 0; foreach (Addin addin in addins) { @@ -377,7 +377,7 @@ namespace OpenSim.Framework r["enabled"] = rep.Enabled == true ? true : false; r["name"] = rep.Name; r["url"] = rep.Url; - + res.Add(count.ToString(), r); count++; } @@ -493,7 +493,7 @@ namespace OpenSim.Framework } - + #region Util private void Testing() { @@ -537,15 +537,15 @@ namespace OpenSim.Framework ArrayList xlist = new ArrayList(); ArrayList list = new ArrayList(); - try - { - list.AddRange(PluginRegistry.GetAddins()); - } - catch (Exception) - { - Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[]; - return x; - } + try + { + list.AddRange(PluginRegistry.GetAddins()); + } + catch (Exception) + { + Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[]; + return x; + } foreach (Addin addin in list) { @@ -559,5 +559,5 @@ namespace OpenSim.Framework return addins; } #endregion Util - } + } } diff --git a/OpenSim/Framework/PrimeNumberHelper.cs b/OpenSim/Framework/PrimeNumberHelper.cs index 477c274c3b..5a1b3b2903 100644 --- a/OpenSim/Framework/PrimeNumberHelper.cs +++ b/OpenSim/Framework/PrimeNumberHelper.cs @@ -35,7 +35,7 @@ namespace OpenSim.Framework public static class PrimeNumberHelper { /// - /// Precalculated prime numbers. + /// Precalculated prime numbers. /// private static readonly int[] Primes = new int[] { diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs index 6a12a45307..29985d2586 100644 --- a/OpenSim/Framework/PrimitiveBaseShape.cs +++ b/OpenSim/Framework/PrimitiveBaseShape.cs @@ -238,8 +238,8 @@ namespace OpenSim.Framework SculptTexture = prim.Sculpt.SculptTexture; SculptType = (byte)prim.Sculpt.Type; } - else - { + else + { SculptType = (byte)OpenMetaverse.SculptType.None; } } diff --git a/OpenSim/Framework/PriorityQueue.cs b/OpenSim/Framework/PriorityQueue.cs index fec01da4bf..5b9185e5c8 100644 --- a/OpenSim/Framework/PriorityQueue.cs +++ b/OpenSim/Framework/PriorityQueue.cs @@ -57,11 +57,11 @@ namespace OpenSim.Framework private Dictionary m_lookupTable; // internal state used to ensure the deqeues are spread across the priority - // queues "fairly". queuecounts is the amount to pull from each queue in + // queues "fairly". queuecounts is the amount to pull from each queue in // each pass. weighted towards the higher priority queues private uint m_nextQueue = 0; private uint m_countFromQueue = 0; - // first queues are imediate, so no counts + // first queues are imediate, so no counts // private uint[] m_queueCounts = { 0, 0, 8, 4, 4, 2, 2, 2, 2, 1, 1, 1 }; private uint[] m_queueCounts = {0, 0, 8, 8, 5, 4, 3, 2, 1, 1, 1, 1}; // this is ava, ava, attach, <10m, 20,40,80,160m,320,640,1280, + @@ -105,7 +105,7 @@ namespace OpenSim.Framework int count = 0; for (int i = 0; i < m_heaps.Length; ++i) count += m_heaps[i].Count; - + return count; } } @@ -170,26 +170,26 @@ namespace OpenSim.Framework return true; } } - + // To get the fair queing, we cycle through each of the - // queues when finding an element to dequeue. + // queues when finding an element to dequeue. // We pull (NumberOfQueues - QueueIndex) items from each queue in order // to give lower numbered queues a higher priority and higher percentage - // of the bandwidth. - + // of the bandwidth. + // Check for more items to be pulled from the current queue if (m_heaps[m_nextQueue].Count > 0 && m_countFromQueue > 0) { m_countFromQueue--; - + MinHeapItem item = m_heaps[m_nextQueue].RemoveMin(); m_lookupTable.Remove(item.Value.Entity.LocalId); timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); value = item.Value; - + return true; } - + // Find the next non-immediate queue with updates in it for (uint i = NumberOfImmediateQueues; i < NumberOfQueues; ++i) { @@ -198,7 +198,7 @@ namespace OpenSim.Framework m_nextQueue = NumberOfImmediateQueues; m_countFromQueue = m_queueCounts[m_nextQueue]; - + if (m_heaps[m_nextQueue].Count > 0) { m_countFromQueue--; @@ -218,7 +218,7 @@ namespace OpenSim.Framework /// /// Reapply the prioritization function to each of the updates currently - /// stored in the priority queues. + /// stored in the priority queues. /// /// The port by which http communication occurs with the region (most noticeably, CAPS communication) /// @@ -389,17 +389,17 @@ namespace OpenSim.Framework /// /// A well-formed URI for the host region server (namely "http://" + ExternalHostName) /// - + public string ServerURI { - get { + get { if ( m_serverURI != string.Empty ) { return m_serverURI; } else { return "http://" + m_externalHostName + ":" + m_httpPort + "/"; } - } - set { + } + set { if ( value.EndsWith("/") ) { m_serverURI = value; } else { @@ -749,10 +749,10 @@ namespace OpenSim.Framework m_physPrimMax = config.GetInt("PhysicalPrimMax", 0); allKeys.Remove("PhysicalPrimMax"); - + m_clampPrimSize = config.GetBoolean("ClampPrimSize", false); allKeys.Remove("ClampPrimSize"); - + m_objectCapacity = config.GetInt("MaxPrims", 15000); allKeys.Remove("MaxPrims"); @@ -766,12 +766,12 @@ namespace OpenSim.Framework string mapTileStaticUUID = config.GetString("MaptileStaticUUID", UUID.Zero.ToString()); if (UUID.TryParse(mapTileStaticUUID.Trim(), out m_maptileStaticUUID)) { - config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString()); + config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString()); } MaptileStaticFile = config.GetString("MaptileStaticFile", String.Empty); allKeys.Remove("MaptileStaticFile"); - + #endregion AgentCapacity = config.GetInt("MaxAgents", 100); @@ -919,10 +919,10 @@ namespace OpenSim.Framework if (m_physPrimMin > 0) config.Set("PhysicalPrimMax", m_physPrimMin); - + if (m_physPrimMax > 0) config.Set("PhysicalPrimMax", m_physPrimMax); - + config.Set("ClampPrimSize", m_clampPrimSize.ToString()); if (m_objectCapacity > 0) @@ -1038,7 +1038,7 @@ namespace OpenSim.Framework configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING, "Free form string describing the type of region", String.Empty, true); - + configMember.addConfigurationOption("region_static_maptile", ConfigurationOption.ConfigurationTypes.TYPE_UUID, "UUID of a texture to use as the map for this region", m_maptileStaticUUID.ToString(), true); } @@ -1090,7 +1090,7 @@ namespace OpenSim.Framework configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, "Max objects this sim will hold", "15000", true); - + configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, "Max avatars this sim will hold", "100", true); @@ -1307,8 +1307,8 @@ namespace OpenSim.Framework kvp["http_port"] = HttpPort.ToString(); kvp["internal_ip_address"] = InternalEndPoint.Address.ToString(); kvp["internal_port"] = InternalEndPoint.Port.ToString(); - // TODO: Remove in next major version - kvp["alternate_ports"] = "False"; + // TODO: Remove in next major version + kvp["alternate_ports"] = "False"; kvp["server_uri"] = ServerURI; return kvp; diff --git a/OpenSim/Framework/RegionSettings.cs b/OpenSim/Framework/RegionSettings.cs index dec01ea6be..c2947a298b 100644 --- a/OpenSim/Framework/RegionSettings.cs +++ b/OpenSim/Framework/RegionSettings.cs @@ -91,7 +91,7 @@ namespace OpenSim.Framework string[] parts = str.Split(','); if (parts.Length != 3) throw new ArgumentException("Invalid string: " + str); - + SpawnPoint sp = new SpawnPoint(); sp.Yaw = float.Parse(parts[0]); sp.Pitch = float.Parse(parts[1]); @@ -105,7 +105,7 @@ namespace OpenSim.Framework public delegate void SaveDelegate(RegionSettings rs); public event SaveDelegate OnSave; - + /// /// These appear to be terrain textures that are shipped with the client. /// @@ -454,24 +454,24 @@ namespace OpenSim.Framework get { return m_LoadedCreationDateTime; } set { m_LoadedCreationDateTime = value; } } - + public String LoadedCreationDate { - get - { + get + { TimeSpan ts = new TimeSpan(0, 0, LoadedCreationDateTime); DateTime stamp = new DateTime(1970, 1, 1) + ts; - return stamp.ToLongDateString(); + return stamp.ToLongDateString(); } } public String LoadedCreationTime { - get - { + get + { TimeSpan ts = new TimeSpan(0, 0, LoadedCreationDateTime); DateTime stamp = new DateTime(1970, 1, 1) + ts; - return stamp.ToLongTimeString(); + return stamp.ToLongTimeString(); } } diff --git a/OpenSim/Framework/RestClient.cs b/OpenSim/Framework/RestClient.cs index 26237deae4..0166d9d37e 100644 --- a/OpenSim/Framework/RestClient.cs +++ b/OpenSim/Framework/RestClient.cs @@ -156,7 +156,7 @@ namespace OpenSim.Framework public void Dispose() { Dispose(true); - GC.SuppressFinalize(this); + GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index e66d5be192..9458625667 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs @@ -44,7 +44,7 @@ namespace OpenSim.Framework Material = -2 } - + #region SL / file extension / content-type conversions /// @@ -175,10 +175,10 @@ namespace OpenSim.Framework new TypeMapping(AssetType.Folder, FolderType.CurrentOutfit, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"), new TypeMapping(AssetType.Folder, FolderType.Outfit, "application/vnd.ll.outfitfolder", "outfitfolder"), new TypeMapping(AssetType.Folder, FolderType.MyOutfits, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"), - + // This next mappping is an asset to inventory item mapping. // Note: LL stores folders as assets of type Folder = 8, and it has a corresponding InventoryType = 8 - // OpenSim doesn't store folders as assets, so this mapping should only be used when parsing things from the viewer to the server + // OpenSim doesn't store folders as assets, so this mapping should only be used when parsing things from the viewer to the server new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"), // OpenSim specific @@ -198,7 +198,7 @@ namespace OpenSim.Framework inventory2Content = new Dictionary(); content2Asset = new Dictionary(); content2Inventory = new Dictionary(); - + foreach (TypeMapping mapping in MAPPINGS) { sbyte assetType = mapping.AssetTypeCode; @@ -226,7 +226,7 @@ namespace OpenSim.Framework } } } - + public static string SLAssetTypeToContentType(int assetType) { string contentType; @@ -406,7 +406,7 @@ namespace OpenSim.Framework if(data[0] == "inv_item") { skipInventoryItem(reader); - } + } else if (line.IndexOf('{') >= 0) { throw new NotANotecardFormatException(reader.LineNumber); @@ -462,7 +462,7 @@ namespace OpenSim.Framework { int length = Int32.Parse(data[2]); notecardString = reader.getBlock(length); - } + } else if (line.IndexOf('{') >= 0) { throw new NotANotecardFormatException(reader.LineNumber); diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs index ab3c285578..9081411129 100644 --- a/OpenSim/Framework/Serialization/ArchiveConstants.cs +++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs @@ -72,12 +72,12 @@ namespace OpenSim.Framework.Serialization /// Path for region settings. /// public const string SETTINGS_PATH = "settings/"; - + /// /// Path for region settings. /// public const string LANDDATA_PATH = "landdata/"; - + /// /// Path for user profiles /// diff --git a/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs b/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs index 55640ac6a8..1523fa9e0b 100644 --- a/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs +++ b/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs @@ -106,13 +106,13 @@ namespace OpenSim.Framework.Serialization.External { errors = true; parseExceptionAction(nodeToFill, nodeName, e); - + if (xtr.EOF) { m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to unexpected end of XML"); break; } - + if (++numErrors == 10) { m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to too many parsing errors"); @@ -369,7 +369,7 @@ namespace OpenSim.Framework.Serialization.External break; case XmlNodeType.XmlDeclaration: - // For various reasons, not all serializations have xml declarations (or consistent ones) + // For various reasons, not all serializations have xml declarations (or consistent ones) // and as it's embedded inside a byte stream we don't need it anyway, so ignore. break; diff --git a/OpenSim/Framework/Serialization/External/OspResolver.cs b/OpenSim/Framework/Serialization/External/OspResolver.cs index fa7160f874..a1e9d554bf 100644 --- a/OpenSim/Framework/Serialization/External/OspResolver.cs +++ b/OpenSim/Framework/Serialization/External/OspResolver.cs @@ -35,13 +35,13 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Framework.Serialization { /// - /// Resolves OpenSim Profile Anchors (OSPA). An OSPA is a string used to provide information for + /// Resolves OpenSim Profile Anchors (OSPA). An OSPA is a string used to provide information for /// identifying user profiles or supplying a simple name if no profile is available. /// public class OspResolver { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + public const string OSPA_PREFIX = "ospa:"; public const string OSPA_NAME_KEY = "n"; public const string OSPA_NAME_VALUE_SEPARATOR = " "; @@ -76,7 +76,7 @@ namespace OpenSim.Framework.Serialization return null; } - + /// /// Make an OSPA given a user name /// @@ -89,17 +89,17 @@ namespace OpenSim.Framework.Serialization // m_log.DebugFormat("[OSP RESOLVER]: Made OSPA {0} for {1} {2}", ospa, firstName, lastName); // System.Console.WriteLine("[OSP RESOLVER]: Made OSPA {0} for {1} {2}", ospa, firstName, lastName); - + return ospa; } - + /// /// Resolve an osp string into the most suitable internal OpenSim identifier. /// - /// + /// /// In some cases this will be a UUID if a suitable profile exists on the system. In other cases, this may /// just return the same identifier after creating a temporary profile. - /// + /// /// /// /// @@ -111,14 +111,14 @@ namespace OpenSim.Framework.Serialization if (!ospa.StartsWith(OSPA_PREFIX)) { // m_log.DebugFormat("[OSP RESOLVER]: ResolveOspa() got unrecognized format [{0}]", ospa); - return UUID.Zero; + return UUID.Zero; } // m_log.DebugFormat("[OSP RESOLVER]: Resolving {0}", ospa); - + string ospaMeat = ospa.Substring(OSPA_PREFIX.Length); string[] ospaTuples = ospaMeat.Split(OSPA_TUPLE_SEPARATOR_ARRAY); - + foreach (string tuple in ospaTuples) { int tupleSeparatorIndex = tuple.IndexOf(OSPA_PAIR_SEPARATOR); @@ -128,17 +128,17 @@ namespace OpenSim.Framework.Serialization m_log.WarnFormat("[OSP RESOLVER]: Ignoring non-tuple component {0} in OSPA {1}", tuple, ospa); continue; } - + string key = tuple.Remove(tupleSeparatorIndex).Trim(); string value = tuple.Substring(tupleSeparatorIndex + 1).Trim(); - + if (OSPA_NAME_KEY == key) return ResolveOspaName(value, userService); } - + return UUID.Zero; } - + /// /// Hash a profile name into a UUID /// @@ -148,7 +148,7 @@ namespace OpenSim.Framework.Serialization { return new UUID(Utils.MD5(Encoding.Unicode.GetBytes(name)), 0); } - + /// /// Resolve an OSPI name by querying existing persistent user profiles. If there is no persistent user profile /// then a temporary user profile is inserted in the cache. @@ -164,13 +164,13 @@ namespace OpenSim.Framework.Serialization return UUID.Zero; int nameSeparatorIndex = name.IndexOf(OSPA_NAME_VALUE_SEPARATOR); - + if (nameSeparatorIndex < 0) { m_log.WarnFormat("[OSP RESOLVER]: Ignoring unseparated name {0}", name); return UUID.Zero; } - + string firstName = name.Remove(nameSeparatorIndex).TrimEnd(); string lastName = name.Substring(nameSeparatorIndex + 1).TrimStart(); @@ -178,14 +178,14 @@ namespace OpenSim.Framework.Serialization if (account != null) { // m_log.DebugFormat( -// "[OSP RESOLVER]: Found user account with uuid {0} for {1} {2}", +// "[OSP RESOLVER]: Found user account with uuid {0} for {1} {2}", // account.PrincipalID, firstName, lastName); - + return account.PrincipalID; } // else // { -// m_log.DebugFormat("[OSP RESOLVER]: No resolved OSPA user account for {0}", name); +// m_log.DebugFormat("[OSP RESOLVER]: No resolved OSPA user account for {0}", name); // } // XXX: Disable temporary user profile creation for now as implementation is incomplete - justincc @@ -194,11 +194,11 @@ namespace OpenSim.Framework.Serialization tempUserProfile.FirstName = firstName; tempUserProfile.SurName = lastName; tempUserProfile.ID = HashName(tempUserProfile.Name); - + m_log.DebugFormat( "[OSP RESOLVER]: Adding temporary user profile for {0} {1}", tempUserProfile.Name, tempUserProfile.ID); commsManager.UserService.AddTemporaryUserProfile(tempUserProfile); - + return tempUserProfile.ID; */ diff --git a/OpenSim/Framework/Serialization/External/RegionSettingsSerializer.cs b/OpenSim/Framework/Serialization/External/RegionSettingsSerializer.cs index 19468c3b2a..617c451fe0 100644 --- a/OpenSim/Framework/Serialization/External/RegionSettingsSerializer.cs +++ b/OpenSim/Framework/Serialization/External/RegionSettingsSerializer.cs @@ -50,7 +50,7 @@ namespace OpenSim.Framework.Serialization.External { return Deserialize(Encoding.ASCII.GetString(serializedSettings, 0, serializedSettings.Length)); } - + /// /// Deserialize settings /// @@ -60,14 +60,14 @@ namespace OpenSim.Framework.Serialization.External public static RegionSettings Deserialize(string serializedSettings) { RegionSettings settings = new RegionSettings(); - + StringReader sr = new StringReader(serializedSettings); XmlTextReader xtr = new XmlTextReader(sr); - + xtr.ReadStartElement("RegionSettings"); - + xtr.ReadStartElement("General"); - + while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement) { switch (xtr.Name) @@ -113,10 +113,10 @@ namespace OpenSim.Framework.Serialization.External break; } } - + xtr.ReadEndElement(); xtr.ReadStartElement("GroundTextures"); - + while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement) { switch (xtr.Name) @@ -159,10 +159,10 @@ namespace OpenSim.Framework.Serialization.External break; } } - + xtr.ReadEndElement(); xtr.ReadStartElement("Terrain"); - + while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement) { switch (xtr.Name) @@ -212,19 +212,19 @@ namespace OpenSim.Framework.Serialization.External xtr.Close(); sr.Close(); - + return settings; } - + public static string Serialize(RegionSettings settings) { StringWriter sw = new StringWriter(); XmlTextWriter xtw = new XmlTextWriter(sw); xtw.Formatting = Formatting.Indented; xtw.WriteStartDocument(); - + xtw.WriteStartElement("RegionSettings"); - + xtw.WriteStartElement("General"); xtw.WriteElementString("AllowDamage", settings.AllowDamage.ToString()); xtw.WriteElementString("AllowLandResell", settings.AllowLandResell.ToString()); @@ -255,7 +255,7 @@ namespace OpenSim.Framework.Serialization.External xtw.WriteElementString("ElevationHighSE", settings.Elevation2SE.ToString()); xtw.WriteElementString("ElevationHighNE", settings.Elevation2NE.ToString()); xtw.WriteEndElement(); - + xtw.WriteStartElement("Terrain"); xtw.WriteElementString("WaterHeight", settings.WaterHeight.ToString()); xtw.WriteElementString("TerrainRaiseLimit", settings.TerrainRaiseLimit.ToString()); @@ -275,12 +275,12 @@ namespace OpenSim.Framework.Serialization.External xtw.WriteElementString("SpawnPoint", sp.ToString()); } xtw.WriteEndElement(); - + xtw.WriteEndElement(); - + xtw.Close(); sw.Close(); - + return sw.ToString(); } } diff --git a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs index 994cede575..9b02553d3a 100644 --- a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs +++ b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs @@ -36,9 +36,9 @@ using log4net; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Services.Interfaces; - + namespace OpenSim.Framework.Serialization.External -{ +{ /// /// Serialize and deserialize user inventory items as an external format. /// @@ -49,14 +49,14 @@ namespace OpenSim.Framework.Serialization.External private static Dictionary> m_InventoryItemXmlProcessors = new Dictionary>(); - #region InventoryItemBase Processor initialization + #region InventoryItemBase Processor initialization static UserInventoryItemSerializer() { m_InventoryItemXmlProcessors.Add("Name", ProcessName); m_InventoryItemXmlProcessors.Add("ID", ProcessID); m_InventoryItemXmlProcessors.Add("InvType", ProcessInvType); m_InventoryItemXmlProcessors.Add("CreatorUUID", ProcessCreatorUUID); - m_InventoryItemXmlProcessors.Add("CreatorID", ProcessCreatorID); + m_InventoryItemXmlProcessors.Add("CreatorID", ProcessCreatorID); m_InventoryItemXmlProcessors.Add("CreatorData", ProcessCreatorData); m_InventoryItemXmlProcessors.Add("CreationDate", ProcessCreationDate); m_InventoryItemXmlProcessors.Add("Owner", ProcessOwner); @@ -73,7 +73,7 @@ namespace OpenSim.Framework.Serialization.External m_InventoryItemXmlProcessors.Add("GroupID", ProcessGroupID); m_InventoryItemXmlProcessors.Add("GroupOwned", ProcessGroupOwned); } - #endregion + #endregion #region InventoryItemBase Processors private static void ProcessName(InventoryItemBase item, XmlReader reader) @@ -189,7 +189,7 @@ namespace OpenSim.Framework.Serialization.External { return Deserialize(Encoding.ASCII.GetString(serialization, 0, serialization.Length)); } - + /// /// Deserialize settings /// @@ -212,8 +212,8 @@ namespace OpenSim.Framework.Serialization.External //m_log.DebugFormat("[XXX]: parsed InventoryItemBase {0} - {1}", obj.Name, obj.UUID); return item; - } - + } + public static string Serialize(InventoryItemBase inventoryItem, Dictionary options, IUserAccountService userAccountService) { StringWriter sw = new StringWriter(); @@ -294,11 +294,11 @@ namespace OpenSim.Framework.Serialization.External } writer.WriteEndElement(); - + writer.Close(); sw.Close(); - + return sw.ToString(); - } + } } } diff --git a/OpenSim/Framework/Serialization/External/UserProfileSerializer.cs b/OpenSim/Framework/Serialization/External/UserProfileSerializer.cs index c685a157e1..34eaa990cd 100644 --- a/OpenSim/Framework/Serialization/External/UserProfileSerializer.cs +++ b/OpenSim/Framework/Serialization/External/UserProfileSerializer.cs @@ -42,31 +42,31 @@ namespace OpenSim.Framework.Serialization.External { public const int MAJOR_VERSION = 0; public const int MINOR_VERSION = 1; - + public static string Serialize(UUID userID, string firstName, string lastName) { StringWriter sw = new StringWriter(); XmlTextWriter xtw = new XmlTextWriter(sw); xtw.Formatting = Formatting.Indented; xtw.WriteStartDocument(); - + xtw.WriteStartElement("user_profile"); xtw.WriteAttributeString("major_version", MAJOR_VERSION.ToString()); xtw.WriteAttributeString("minor_version", MINOR_VERSION.ToString()); - + xtw.WriteElementString("name", firstName + " " + lastName); xtw.WriteElementString("id", userID.ToString()); xtw.WriteElementString("about", ""); - + // Not sure if we're storing this yet, need to take a look // xtw.WriteElementString("Url", profile.Url); // or, indeed, interests xtw.WriteEndElement(); - + xtw.Close(); sw.Close(); - + return sw.ToString(); } } diff --git a/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs b/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs index f2060abfbc..7dfb87b5ef 100644 --- a/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Framework.Serialization")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,7 +25,7 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/Framework/Serialization/TarArchiveWriter.cs b/OpenSim/Framework/Serialization/TarArchiveWriter.cs index 2a3bc4805d..a5c3d0ae6e 100644 --- a/OpenSim/Framework/Serialization/TarArchiveWriter.cs +++ b/OpenSim/Framework/Serialization/TarArchiveWriter.cs @@ -113,7 +113,7 @@ namespace OpenSim.Framework.Serialization lock (m_bw) { m_bw.Write(finalZeroPadding); - + m_bw.Flush(); m_bw.Close(); } @@ -149,7 +149,7 @@ namespace OpenSim.Framework.Serialization { // m_log.DebugFormat( // "[TAR ARCHIVE WRITER]: Data for {0} is {1} bytes", filePath, (null == data ? "null" : data.Length.ToString())); - + byte[] header = new byte[512]; // file path field (100) @@ -208,18 +208,18 @@ namespace OpenSim.Framework.Serialization { // Write out header m_bw.Write(header); - + // Write out data // An IOException occurs if we try to write out an empty array in Mono 2.6 if (data.Length > 0) m_bw.Write(data); - + if (data.Length % 512 != 0) { int paddingRequired = 512 - (data.Length % 512); - + //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Padding data with {0} bytes", paddingRequired); - + byte[] padding = new byte[paddingRequired]; m_bw.Write(padding); } diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 1d4deac7bc..f761813560 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -68,9 +68,9 @@ namespace OpenSim.Framework.Servers private int m_periodDiagnosticTimerMS = 60 * 60 * 1000; private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); - + /// - /// Random uuid for private data + /// Random uuid for private data /// protected string m_osSecret = String.Empty; @@ -85,7 +85,7 @@ namespace OpenSim.Framework.Servers // Random uuid for private data m_osSecret = UUID.Random().ToString(); } - + /// /// Must be overriden by child classes for their own server specific startup behaviour. /// @@ -104,10 +104,10 @@ namespace OpenSim.Framework.Servers m_periodicDiagnosticsTimer.Interval = m_periodDiagnosticTimerMS; m_periodicDiagnosticsTimer.Enabled = true; } - } + } protected override void ShutdownSpecific() - { + { m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); RemovePIDFile(); @@ -117,12 +117,12 @@ namespace OpenSim.Framework.Servers if (!SuppressExit) Environment.Exit(0); } - + /// /// Provides a list of help topics that are available. Overriding classes should append their topics to the /// information returned when the base method is called. /// - /// + /// /// /// A list of strings that represent different help topics on which more information is available /// @@ -148,7 +148,7 @@ namespace OpenSim.Framework.Servers public virtual void Startup() { m_log.Info("[STARTUP]: Beginning startup processing"); - + m_log.Info("[STARTUP]: version: " + m_version + Environment.NewLine); // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and // the clr version number doesn't match the project version number under Mono. @@ -156,7 +156,7 @@ namespace OpenSim.Framework.Servers m_log.InfoFormat( "[STARTUP]: Operating system version: {0}, .NET platform {1}, {2}-bit\n", Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32"); - + try { StartupSpecific(); @@ -167,18 +167,18 @@ namespace OpenSim.Framework.Servers (e.Message == null || e.Message == String.Empty) ? "Unknown reason":e.Message ); Environment.Exit(1); } - + TimeSpan timeTaken = DateTime.Now - m_startuptime; - + // MainConsole.Instance.OutputFormat( // "PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED. Non-script portion of startup took {0}m {1}s.", // timeTaken.Minutes, timeTaken.Seconds); } - public string osSecret + public string osSecret { // Secret uuid for the simulator - get { return m_osSecret; } + get { return m_osSecret; } } public string StatReport(IOSHttpRequest httpRequest) @@ -187,8 +187,8 @@ namespace OpenSim.Framework.Servers if (httpRequest.Query.ContainsKey("callback")) { return httpRequest.Query["callback"].ToString() + "(" + StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");"; - } - else + } + else { return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version); } diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index e431042c70..fb92b9237a 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -58,7 +58,7 @@ namespace OpenSim.Framework.Servers.HttpServer /// /// This is a pending websocket request before it got an sucessful upgrade response. - /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to + /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to /// start the connection and optionally provide an origin authentication method. /// /// @@ -104,7 +104,7 @@ namespace OpenSim.Framework.Servers.HttpServer new Dictionary(); protected Dictionary m_WebSocketHandlers = - new Dictionary(); + new Dictionary(); protected uint m_port; protected uint m_sslport; @@ -253,7 +253,7 @@ namespace OpenSim.Framework.Servers.HttpServer return new List(m_rpcHandlers.Keys); } - // JsonRPC + // JsonRPC public bool AddJsonRPCHandler(string method, JsonRPCMethod handler) { lock(jsonRpcHandlers) @@ -459,11 +459,11 @@ namespace OpenSim.Framework.Servers.HttpServer dWebSocketRequestDelegate(req.Url.AbsolutePath, new WebSocketHttpServerHandler(req, context, 8192)); return; } - + OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); resp.ReuseContext = true; // resp.ReuseContext = false; - HandleRequest(req, resp); + HandleRequest(req, resp); // !!!HACK ALERT!!! // There seems to be a bug in the underlying http code that makes subsequent requests @@ -554,7 +554,7 @@ namespace OpenSim.Framework.Servers.HttpServer LogIncomingToStreamHandler(request, requestHandler); response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. - + if (requestHandler is IStreamedRequestHandler) { IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; @@ -630,16 +630,16 @@ namespace OpenSim.Framework.Servers.HttpServer case "text/html": if (DebugLevel >= 3) LogIncomingToContentTypeHandler(request); - + buffer = HandleHTTPRequest(request, response); break; - + case "application/llsd+xml": case "application/xml+llsd": case "application/llsd+json": if (DebugLevel >= 3) LogIncomingToContentTypeHandler(request); - + buffer = HandleLLSDRequests(request, response); break; @@ -649,7 +649,7 @@ namespace OpenSim.Framework.Servers.HttpServer buffer = HandleJsonRpcRequests(request, response); break; - + case "text/xml": case "application/xml": case "application/json": @@ -666,7 +666,7 @@ namespace OpenSim.Framework.Servers.HttpServer { if (DebugLevel >= 3) LogIncomingToContentTypeHandler(request); - + buffer = HandleLLSDRequests(request, response); } // m_log.DebugFormat("[BASE HTTP SERVER]: Checking for HTTP Handler for request {0}", request.RawUrl); @@ -674,18 +674,18 @@ namespace OpenSim.Framework.Servers.HttpServer { if (DebugLevel >= 3) LogIncomingToContentTypeHandler(request); - + buffer = HandleHTTPRequest(request, response); } else { if (DebugLevel >= 3) LogIncomingToXmlRpcHandler(request); - + // generic login request. buffer = HandleXmlRpcRequests(request, response); } - + break; } } @@ -972,7 +972,7 @@ namespace OpenSim.Framework.Servers.HttpServer // private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler) // { // agentHandler = null; -// +// // lock (m_agentHandlers) // { // foreach (IHttpAgentHandler handler in m_agentHandlers.Values) @@ -1171,7 +1171,7 @@ namespace OpenSim.Framework.Servers.HttpServer return buffer; } - // JsonRpc (v2.0 only) + // JsonRpc (v2.0 only) // Batch requests not yet supported private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response) { @@ -1188,7 +1188,7 @@ namespace OpenSim.Framework.Servers.HttpServer jsonRpcResponse.Error.Code = ErrorCode.InternalError; jsonRpcResponse.Error.Message = e.Message; } - + requestStream.Close(); if (jsonRpcRequest != null) @@ -1253,7 +1253,7 @@ namespace OpenSim.Framework.Servers.HttpServer string responseData = string.Empty; responseData = jsonRpcResponse.Serialize(); - + byte[] buffer = Encoding.UTF8.GetBytes(responseData); return buffer; } @@ -1533,7 +1533,7 @@ namespace OpenSim.Framework.Servers.HttpServer } } } - + if (String.IsNullOrEmpty(bestMatch)) { llsdHandler = null; @@ -1899,8 +1899,8 @@ namespace OpenSim.Framework.Servers.HttpServer response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; - - + + return buffer; } @@ -1977,7 +1977,7 @@ namespace OpenSim.Framework.Servers.HttpServer throw e; } - m_requestsProcessedStat + m_requestsProcessedStat = new Stat( "HTTPRequestsServed", "Number of inbound HTTP requests processed", @@ -1989,7 +1989,7 @@ namespace OpenSim.Framework.Servers.HttpServer MeasuresOfInterest.AverageChangeOverTime, stat => stat.Value = RequestNumber, StatVerbosity.Debug); - + StatsManager.RegisterStat(m_requestsProcessedStat); } diff --git a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs index d4a1ec3172..01d95e916a 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs @@ -69,13 +69,13 @@ namespace OpenSim.Framework.Servers.HttpServer { StatsManager.RegisterStat( new Stat( - "requests", - "requests", - "Number of requests received by this service endpoint", - "requests", - "service", - string.Format("{0}:{1}", httpMethod, path), - StatType.Pull, + "requests", + "requests", + "Number of requests received by this service endpoint", + "requests", + "service", + string.Format("{0}:{1}", httpMethod, path), + StatType.Pull, MeasuresOfInterest.AverageChangeOverTime, s => s.Value = RequestsReceived, StatVerbosity.Debug)); diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs index 41aa19b67c..7fc9f0b881 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs @@ -47,7 +47,7 @@ namespace OpenSim.Framework.Servers.HttpServer : base(httpMethod, path, name, description) {} protected BaseStreamHandler(string httpMethod, string path, IServiceAuth auth) - : base(httpMethod, path, null, null) + : base(httpMethod, path, null, null) { m_Auth = auth; } @@ -62,7 +62,7 @@ namespace OpenSim.Framework.Servers.HttpServer HttpStatusCode statusCode; if (!m_Auth.Authenticate(httpRequest.Headers, httpResponse.AddHeader, out statusCode)) - { + { httpResponse.StatusCode = (int)statusCode; httpResponse.ContentType = "text/plain"; return new byte[0]; diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs index 1b8854573b..9619e0367e 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs @@ -37,7 +37,7 @@ namespace OpenSim.Framework.Servers.HttpServer /// public abstract class BaseStreamHandlerBasicDOSProtector : BaseRequestHandler, IStreamedRequestHandler { - + private readonly BasicDosProtectorOptions _options; private readonly BasicDOSProtector _dosProtector; @@ -63,7 +63,7 @@ namespace OpenSim.Framework.Servers.HttpServer result = ThrottledRequest(path, request, httpRequest, httpResponse); if (_options.MaxConcurrentSessions > 0) _dosProtector.ProcessEnd(clientstring, endpoint); - + RequestsHandled++; return result; @@ -81,7 +81,7 @@ namespace OpenSim.Framework.Servers.HttpServer return new byte[0]; } - + private string GetRemoteAddr(IOSHttpRequest httpRequest) { string remoteaddr = string.Empty; @@ -101,7 +101,7 @@ namespace OpenSim.Framework.Servers.HttpServer clientstring = GetRemoteAddr(httpRequest); return clientstring; - + } } } diff --git a/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs index cd4b8ffa29..98d33e4537 100644 --- a/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs +++ b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs @@ -33,7 +33,7 @@ namespace OpenSim.Framework.Servers.HttpServer { private readonly GenericHTTPMethod _normalMethod; private readonly GenericHTTPMethod _throttledMethod; - + private readonly BasicDosProtectorOptions _options; private readonly BasicDOSProtector _dosProtector; @@ -41,7 +41,7 @@ namespace OpenSim.Framework.Servers.HttpServer { _normalMethod = normalMethod; _throttledMethod = throttledMethod; - + _options = options; _dosProtector = new BasicDOSProtector(_options); } @@ -60,7 +60,7 @@ namespace OpenSim.Framework.Servers.HttpServer return process; } - + private string GetRemoteAddr(Hashtable request) { string remoteaddr = ""; diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs index d162bc12fb..3a04074b1d 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs @@ -45,26 +45,26 @@ namespace OpenSim.Framework.Servers.HttpServer // // the handlers - it is NOT required to be an actual agent header // // value. // bool AddAgentHandler(string agent, IHttpAgentHandler handler); - + /// /// Add a handler for an HTTP request. /// /// - /// This handler can actually be invoked either as - /// - /// http://:/?method= - /// + /// This handler can actually be invoked either as + /// + /// http://:/?method= + /// /// or - /// + /// /// http://: - /// + /// /// if the method name starts with a slash. For example, AddHTTPHandler("/object/", ...) on a standalone region /// server will register a handler that can be invoked with either - /// + /// /// http://localhost:9000/?method=/object/ - /// + /// /// or - /// + /// /// http://localhost:9000/object/ /// /// In addition, the handler invoked by the HTTP server for any request is the one when best matches the request @@ -87,7 +87,7 @@ namespace OpenSim.Framework.Servers.HttpServer /// handle the LLSD response /// bool AddLLSDHandler(string path, LLSDMethod handler); - + /// /// Add a stream handler to the http server. If the handler already exists, then nothing happens. /// @@ -98,7 +98,7 @@ namespace OpenSim.Framework.Servers.HttpServer bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive); bool AddJsonRPCHandler(string method, JsonRPCMethod handler); - + /// /// Websocket HTTP server handlers. /// @@ -108,7 +108,7 @@ namespace OpenSim.Framework.Servers.HttpServer void RemoveWebSocketHandler(string servicepath); - + /// /// Gets the XML RPC handler for given method name /// @@ -125,7 +125,7 @@ namespace OpenSim.Framework.Servers.HttpServer // /// // /// // bool RemoveAgentHandler(string agent, IHttpAgentHandler handler); - + /// /// Remove an HTTP handler /// @@ -134,15 +134,15 @@ namespace OpenSim.Framework.Servers.HttpServer void RemoveHTTPHandler(string httpMethod, string path); void RemovePollServiceHTTPHandler(string httpMethod, string path); - + bool RemoveLLSDHandler(string path, LLSDMethod handler); - + void RemoveStreamHandler(string httpMethod, string path); void RemoveXmlRPCHandler(string method); void RemoveJsonRPCHandler(string method); - + string GetHTTP404(string host); string GetHTTP500(); diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs index b8541cbe4c..62d92fb1ea 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs @@ -83,7 +83,7 @@ namespace OpenSim.Framework.Servers.HttpServer { void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse); } - + public interface IGenericHTTPHandler : IRequestHandler { Hashtable Handle(string path, Hashtable request); diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs index f3faf4f6d4..411ee3161c 100644 --- a/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs @@ -43,7 +43,7 @@ namespace OpenSim.Framework.Servers.HttpServer public class JsonRpcRequestManager { static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + public JsonRpcRequestManager() { } @@ -188,6 +188,6 @@ namespace OpenSim.Framework.Servers.HttpServer return true; } - + } } diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs b/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs index 2c50587794..91d284bedf 100644 --- a/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs +++ b/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs @@ -144,7 +144,7 @@ namespace OpenSim.Framework.Servers.HttpServer { } - return result; + return result; } } } diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs index 05ec6dc8c4..1a6b8cf5f9 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs @@ -155,11 +155,11 @@ namespace OpenSim.Framework.Servers.HttpServer private string _userAgent; internal IHttpRequest IHttpRequest - { + { get { return _request; } } - internal IHttpClientContext IHttpClientContext + internal IHttpClientContext IHttpClientContext { get { return _context; } } @@ -192,19 +192,19 @@ namespace OpenSim.Framework.Servers.HttpServer // ignore } } - + if (null != req.Headers["content-type"]) _contentType = _request.Headers["content-type"]; if (null != req.Headers["user-agent"]) _userAgent = req.Headers["user-agent"]; - + if (null != req.Headers["remote_addr"]) { try { IPAddress addr = IPAddress.Parse(req.Headers["remote_addr"]); // sometimes req.Headers["remote_port"] returns a comma separated list, so use - // the first one in the list and log it + // the first one in the list and log it string[] strPorts = req.Headers["remote_port"].Split(new char[] { ',' }); if (strPorts.Length > 1) { @@ -216,7 +216,7 @@ namespace OpenSim.Framework.Servers.HttpServer } catch (FormatException) { - _log.ErrorFormat("[OSHttpRequest]: format exception on addr/port {0}:{1}, ignoring", + _log.ErrorFormat("[OSHttpRequest]: format exception on addr/port {0}:{1}, ignoring", req.Headers["remote_addr"], req.Headers["remote_port"]); } } diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs index ccf9c9149d..d7744fceea 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs @@ -115,7 +115,7 @@ namespace OpenSim.Framework.Servers.HttpServer public bool KeepAlive { - get + get { return _httpResponse.Connection == ConnectionType.KeepAlive; } diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs index a736c8b753..88e3068bc1 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs @@ -91,7 +91,7 @@ namespace OpenSim.Framework.Servers.HttpServer /// 300 Redirect: different presentation forms available, take a pick /// RedirectMultipleChoices = 300, - + /// /// 301 Redirect: requested resource has moved and now lives somewhere else /// diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 3fd3bf703c..8ace7a99d0 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -46,14 +46,14 @@ namespace OpenSim.Framework.Servers.HttpServer public RequestMethod Request; public UUID Id; public int TimeOutms; - public EventType Type; + public EventType Type; public enum EventType : int { LongPoll = 0, LslHttp = 1, Inventory = 2, - Texture = 3, + Texture = 3, Mesh = 4 } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index ffcad0ffdf..936146d904 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -80,7 +80,7 @@ namespace OpenSim.Framework.Servers.HttpServer startInfo.ThreadPoolName = "PoolService"; m_threadPool = new SmartThreadPool(startInfo); - + } public void Start() @@ -109,7 +109,7 @@ namespace OpenSim.Framework.Servers.HttpServer true, null, 1000 * 60 * 10); - + } diff --git a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs index 398179fac2..9b663bac90 100644 --- a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Framework.Servers.HttpServer")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,7 +25,7 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs index ad69cd22cb..68073c1164 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs @@ -291,5 +291,5 @@ namespace OpenSim.Framework.Servers.HttpServer serializer.Serialize(xmlWriter, response); } } - } + } } \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs index c2925e33f0..c8af90f75c 100644 --- a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs @@ -75,7 +75,7 @@ namespace OpenSim.Framework.Servers.HttpServer public event PongDelegate OnPong; /// - /// This is a regular HTTP Request... This may be removed in the future. + /// This is a regular HTTP Request... This may be removed in the future. /// // public event RegularHttpRequestDelegate OnRegularHttpRequest; @@ -93,9 +93,9 @@ namespace OpenSim.Framework.Servers.HttpServer /// When the websocket is closed, this will be fired. /// public event CloseDelegate OnClose; - + /// - /// Set this delegate to allow your module to validate the origin of the + /// Set this delegate to allow your module to validate the origin of the /// Websocket request. Primary line of defense against cross site scripting /// public ValidateHandshake HandshakeValidateMethodOverride = null; @@ -181,7 +181,7 @@ namespace OpenSim.Framework.Servers.HttpServer { throw new InvalidOperationException("The socket has been shutdown"); } - } + } set { if (_networkContext != null && _networkContext.Socket != null) @@ -194,8 +194,8 @@ namespace OpenSim.Framework.Servers.HttpServer } /// - /// This triggers the websocket to start the upgrade process... - /// This is a Generalized Networking 'common sense' helper method. Some people expect to call Start() instead + /// This triggers the websocket to start the upgrade process... + /// This is a Generalized Networking 'common sense' helper method. Some people expect to call Start() instead /// of the more context appropriate HandshakeAndUpgrade() /// public void Start() @@ -261,7 +261,7 @@ namespace OpenSim.Framework.Servers.HttpServer acceptKey = GenerateAcceptKey(websocketKey); string rawaccept = string.Format(HandshakeAcceptText, acceptKey); SendUpgradeSuccess(rawaccept); - + } else @@ -282,7 +282,7 @@ namespace OpenSim.Framework.Servers.HttpServer } /// - /// Generates a handshake response key string based on the client's + /// Generates a handshake response key string based on the client's /// provided key to prove to the client that we're allowing the Websocket /// upgrade of our own free will and we were not coerced into doing it. /// @@ -298,7 +298,7 @@ namespace OpenSim.Framework.Servers.HttpServer SHA1 hashobj = SHA1.Create(); string ret = Convert.ToBase64String(hashobj.ComputeHash(Encoding.UTF8.GetBytes(acceptkey))); hashobj.Clear(); - + return ret; } @@ -310,11 +310,11 @@ namespace OpenSim.Framework.Servers.HttpServer { // Create a new websocket state so we can keep track of data in between network reads. WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true}; - + byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse); - - + + try { @@ -324,7 +324,7 @@ namespace OpenSim.Framework.Servers.HttpServer } // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream. _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState); - + // Write the upgrade handshake success message _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length); _networkContext.Stream.Flush(); @@ -345,7 +345,7 @@ namespace OpenSim.Framework.Servers.HttpServer catch (ObjectDisposedException) { Close(string.Empty); - } + } } /// @@ -369,7 +369,7 @@ namespace OpenSim.Framework.Servers.HttpServer /// /// This is our ugly Async OnReceive event handler. - /// This chunks the input stream based on the length of the provided buffer and processes out + /// This chunks the input stream based on the length of the provided buffer and processes out /// as many frames as it can. It then moves the unprocessed data to the beginning of the buffer. /// /// Our Async State from beginread @@ -390,7 +390,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (_bufferPosition > _bufferLength) { - // Message too big for chunksize.. not sure how this happened... + // Message too big for chunksize.. not sure how this happened... //Close(string.Empty); } @@ -413,7 +413,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (pheader.PayloadLen > (ulong) _maxPayloadBytes) { Close("Invalid Payload size"); - + return; } if (pheader.PayloadLen > 0) @@ -487,7 +487,7 @@ namespace OpenSim.Framework.Servers.HttpServer _socketState.ReceivedBytes.Clear(); _socketState.ExpectedBytes = 0; // do some processing - } + } } } if (offset > 0) @@ -504,7 +504,7 @@ namespace OpenSim.Framework.Servers.HttpServer } else { - // We can't read the stream anymore... + // We can't read the stream anymore... } } catch (IOException) @@ -533,7 +533,7 @@ namespace OpenSim.Framework.Servers.HttpServer textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text; textMessageFrame.Header.IsEnd = true; SendSocket(textMessageFrame.ToBytes()); - + } public void SendData(byte[] data) @@ -657,7 +657,7 @@ namespace OpenSim.Framework.Servers.HttpServer SendSocket(pongFrame.ToBytes()); break; case WebSocketReader.OpCode.Pong: - + PongDelegate pongD = OnPong; if (pongD != null) { @@ -701,7 +701,7 @@ namespace OpenSim.Framework.Servers.HttpServer { textD(this, new WebsocketTextEventArgs() { Data = Encoding.UTF8.GetString(psocketState.ReceivedBytes.ToArray()) }); } - + // Send Done Event! } break; @@ -719,7 +719,7 @@ namespace OpenSim.Framework.Servers.HttpServer { if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Text) { - // Send Done event + // Send Done event TextDelegate textD = OnText; if (textD != null) { @@ -744,9 +744,9 @@ namespace OpenSim.Framework.Servers.HttpServer break; case WebSocketReader.OpCode.Close: Close(string.Empty); - + break; - + } psocketState.Header.SetDefault(); psocketState.ReceivedBytes.Clear(); @@ -837,12 +837,12 @@ namespace OpenSim.Framework.Servers.HttpServer } /// - /// Attempts to read a header off the provided buffer. Returns true, exports a WebSocketFrameheader, + /// Attempts to read a header off the provided buffer. Returns true, exports a WebSocketFrameheader, /// and an int to move the buffer forward when it reads a header. False when it can't read a header /// /// Bytes read from the stream /// Starting place in the stream to begin trying to read from - /// Lenth in the stream to try and read from. Provided for cases where the + /// Lenth in the stream to try and read from. Provided for cases where the /// buffer's length is larger then the data in it /// Outputs the read WebSocket frame header /// Informs the calling stream to move the buffer forward @@ -897,7 +897,7 @@ namespace OpenSim.Framework.Servers.HttpServer oHeader.PayloadLen = BitConverter.ToUInt16(pBuffer, pOffset + index); index += 2; break; - case 127: // we got more this is a bigger frame + case 127: // we got more this is a bigger frame // 8 bytes - uint64 - most significant bit 0 network byte order minumheadersize += 8; if (length < minumheadersize) @@ -909,7 +909,7 @@ namespace OpenSim.Framework.Servers.HttpServer oHeader.PayloadLen = BitConverter.ToUInt64(pBuffer, pOffset + index); index += 8; break; - + } //oHeader.PayloadLeft = oHeader.PayloadLen; // Start the count in case it's chunked over the network. This is different then frame fragmentation if (oHeader.IsMasked) @@ -937,9 +937,9 @@ namespace OpenSim.Framework.Servers.HttpServer /* * RFC6455 nib 0 1 2 3 4 5 6 7 -byt 0 1 2 3 -dec 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +byt 0 1 2 3 +dec 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-------+-+-------------+-------------------------------+ |F|R|R|R| opcode|M| Payload len | Extended payload length | |I|S|S|S| (4) |A| (7) | (16/64) + @@ -963,7 +963,7 @@ dec 0 1 2 3 public static readonly WebSocketFrame DefaultFrame = new WebSocketFrame(){Header = new WebsocketFrameHeader(),WebSocketPayload = new byte[0]}; public WebsocketFrameHeader Header; public byte[] WebSocketPayload; - + public byte[] ToBytes() { Header.PayloadLen = (ulong)WebSocketPayload.Length; @@ -991,7 +991,7 @@ dec 0 1 2 3 public int Mask; /* byt 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+---------------+---------------+ | Octal 1 | Octal 2 | Octal 3 | Octal 4 | +---------------+---------------+---------------+---------------+ @@ -1002,11 +1002,11 @@ byt 0 1 2 3 public UInt64 PayloadLen; //public UInt64 PayloadLeft; - // Payload is X + Y + // Payload is X + Y //public UInt64 ExtensionDataLength; //public UInt64 ApplicationDataLength; public static readonly WebsocketFrameHeader ZeroHeader = WebsocketFrameHeader.HeaderDefault(); - + public void SetDefault() { @@ -1025,16 +1025,16 @@ byt 0 1 2 3 /// /// Returns a byte array representing the Frame header /// - /// This is the frame data payload. The header describes the size of the payload. + /// This is the frame data payload. The header describes the size of the payload. /// If payload is null, a Zero sized payload is assumed /// Returns a byte array representing the frame header public byte[] ToBytes(byte[] payload) { List result = new List(); - + // Squeeze in our opcode and our ending bit. result.Add((byte)((byte)Opcode | (IsEnd?0x80:0x00) )); - + // Again with the three different byte interpretations of size.. //bytesize @@ -1056,7 +1056,7 @@ byt 0 1 2 3 Array.Reverse(payloadLengthByte); result.AddRange(payloadLengthByte); } - + // Only add a payload if it's not null if (payload != null) { @@ -1155,5 +1155,5 @@ byt 0 1 2 3 } - + } diff --git a/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs index f2122080c0..6b2c0ab801 100644 --- a/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs +++ b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs @@ -36,7 +36,7 @@ namespace OpenSim.Framework.Servers.HttpServer { private readonly XmlRpcMethod _normalMethod; private readonly XmlRpcMethod _throttledMethod; - + private readonly BasicDosProtectorOptions _options; private readonly BasicDOSProtector _dosProtector; @@ -44,7 +44,7 @@ namespace OpenSim.Framework.Servers.HttpServer { _normalMethod = normalMethod; _throttledMethod = throttledMethod; - + _options = options; _dosProtector = new BasicDOSProtector(_options); @@ -87,5 +87,5 @@ namespace OpenSim.Framework.Servers.HttpServer } - + } diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs index 57931d449d..ea7b2b56c4 100644 --- a/OpenSim/Framework/Servers/MainServer.cs +++ b/OpenSim/Framework/Servers/MainServer.cs @@ -223,11 +223,11 @@ namespace OpenSim.Framework.Servers { handlers.AppendFormat( "Registered HTTP Handlers for server at {0}:{1}\n", httpServer.ListenIPAddress, httpServer.Port); - + handlers.AppendFormat("* XMLRPC:\n"); foreach (String s in httpServer.GetXmlRpcHandlerKeys()) handlers.AppendFormat("\t{0}\n", s); - + handlers.AppendFormat("* HTTP:\n"); foreach (String s in httpServer.GetHTTPHandlerKeys()) handlers.AppendFormat("\t{0}\n", s); @@ -235,19 +235,19 @@ namespace OpenSim.Framework.Servers handlers.AppendFormat("* HTTP (poll):\n"); foreach (String s in httpServer.GetPollServiceHandlerKeys()) handlers.AppendFormat("\t{0}\n", s); - + handlers.AppendFormat("* JSONRPC:\n"); foreach (String s in httpServer.GetJsonRpcHandlerKeys()) handlers.AppendFormat("\t{0}\n", s); - + // handlers.AppendFormat("* Agent:\n"); // foreach (String s in httpServer.GetAgentHandlerKeys()) // handlers.AppendFormat("\t{0}\n", s); - + handlers.AppendFormat("* LLSD:\n"); foreach (String s in httpServer.GetLLSDHandlerKeys()) handlers.AppendFormat("\t{0}\n", s); - + handlers.AppendFormat("* StreamHandlers ({0}):\n", httpServer.GetStreamHandlerKeys().Count); foreach (String s in httpServer.GetStreamHandlerKeys()) handlers.AppendFormat("\t{0}\n", s); @@ -334,7 +334,7 @@ namespace OpenSim.Framework.Servers { if (port == 0) return Instance; - + if (instance != null && port == Instance.Port) return Instance; diff --git a/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs index 792c62e2c7..4469e7c36d 100644 --- a/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Framework.Servers")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,7 +25,7 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 7b806a4a8d..8965e71a34 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -56,7 +56,7 @@ namespace OpenSim.Framework.Servers protected ICommandConsole m_console; protected OpenSimAppender m_consoleAppender; - protected FileAppender m_logFileAppender; + protected FileAppender m_logFileAppender; protected DateTime m_startuptime; protected string m_startupDirectory = Environment.CurrentDirectory; @@ -81,7 +81,7 @@ namespace OpenSim.Framework.Servers { if (File.Exists(path)) m_log.ErrorFormat( - "[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.", + "[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.", path); try @@ -103,7 +103,7 @@ namespace OpenSim.Framework.Servers m_log.Warn(string.Format("[SERVER BASE]: Could not create PID file at {0} ", path), e); } } - + protected void RemovePIDFile() { if (m_pidFile != String.Empty) @@ -166,11 +166,11 @@ namespace OpenSim.Framework.Servers { // FIXME: This should be done through an interface rather than casting. m_consoleAppender.Console = (ConsoleBase)m_console; - + // If there is no threshold set then the threshold is effectively everything. if (null == m_consoleAppender.Threshold) m_consoleAppender.Threshold = Level.All; - + Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold)); } @@ -205,11 +205,11 @@ namespace OpenSim.Framework.Servers "General", false, "show uptime", "show uptime", "Show server uptime", HandleShow); m_console.Commands.AddCommand( - "General", false, "get log level", "get log level", "Get the current console logging level", + "General", false, "get log level", "get log level", "Get the current console logging level", (mod, cmd) => ShowLogLevel()); m_console.Commands.AddCommand( - "General", false, "set log level", "set log level ", + "General", false, "set log level", "set log level ", "Set the console logging level for this session.", HandleSetLogLevel); m_console.Commands.AddCommand( @@ -222,14 +222,14 @@ namespace OpenSim.Framework.Servers "config get [
    ] []", "Synonym for config show", HandleConfig); - + m_console.Commands.AddCommand( "General", false, "config show", "config show [
    ] []", - "Show config information", + "Show config information", "If neither section nor field are specified, then the whole current configuration is printed." + Environment.NewLine + "If a section is given but not a field, then all fields in that section are printed.", - HandleConfig); + HandleConfig); m_console.Commands.AddCommand( "General", false, "config save", @@ -280,7 +280,7 @@ namespace OpenSim.Framework.Servers "debug threadpool status", "Show current debug threadpool parameters.", HandleDebugThreadpoolStatus); - + m_console.Commands.AddCommand( "Debug", false, "debug threadpool level", "debug threadpool level 0.." + Util.MAX_THREADPOOL_LEVEL, @@ -332,7 +332,7 @@ namespace OpenSim.Framework.Servers { WebUtil.SerializeOSDRequestsPerEndpoint = networkConfig.GetBoolean("SerializeOSDRequests", false); } - + m_serverStatsCollector = new ServerStatsCollector(); m_serverStatsCollector.Initialise(configSource); m_serverStatsCollector.Start(); @@ -432,7 +432,7 @@ namespace OpenSim.Framework.Servers ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); Notice("Available worker threads: {0}", workerThreads); - Notice("Available IOCP threads: {0}", iocpThreads); + Notice("Available IOCP threads: {0}", iocpThreads); } private void HandleDebugThreadpoolSet(string module, string[] args) @@ -488,7 +488,7 @@ namespace OpenSim.Framework.Servers fail = true; } } - + if (fail) { Notice("ERROR: Could not set {0} {1} threads to {2}", poolType, bound, newThreads); @@ -582,7 +582,7 @@ namespace OpenSim.Framework.Servers if (cmdparams.Length > 0) { string firstParam = cmdparams[0].ToLower(); - + switch (firstParam) { case "set": @@ -633,12 +633,12 @@ namespace OpenSim.Framework.Servers { Notice("[{0}]", config.Name); foreach (string key in config.GetKeys()) - Notice(" {0} = {1}", key, config.GetString(key)); + Notice(" {0} = {1}", key, config.GetString(key)); } else { Notice( - "config get {0} {1} : {2}", + "config get {0} {1} : {2}", cmdparams[1], cmdparams[2], config.GetString(cmdparams[2])); } } @@ -692,10 +692,10 @@ namespace OpenSim.Framework.Servers } string rawLevel = cmd[3]; - + ILoggerRepository repository = LogManager.GetRepository(); Level consoleLevel = repository.LevelMap[rawLevel]; - + if (consoleLevel != null) m_consoleAppender.Threshold = consoleLevel; else @@ -770,9 +770,9 @@ namespace OpenSim.Framework.Servers protected void ShowInfo() { Notice(GetVersionText()); - Notice("Startup directory: " + m_startupDirectory); + Notice("Startup directory: " + m_startupDirectory); if (null != m_consoleAppender) - Notice(String.Format("Console log level: {0}", m_consoleAppender.Threshold)); + Notice(String.Format("Console log level: {0}", m_consoleAppender.Threshold)); } /// @@ -873,7 +873,7 @@ namespace OpenSim.Framework.Servers public string GetVersionText() { - return String.Format("Version: {0} (SIMULATION/{1} - SIMULATION/{2})", + return String.Format("Version: {0} (SIMULATION/{1} - SIMULATION/{2})", m_version, VersionInfo.SimulationServiceVersionSupportedMin, VersionInfo.SimulationServiceVersionSupportedMax); } @@ -898,7 +898,7 @@ namespace OpenSim.Framework.Servers foreach (Watchdog.ThreadWatchdogInfo twi in threads) { Thread t = twi.Thread; - + sb.AppendFormat( reportFormat, t.ManagedThreadId, @@ -1005,7 +1005,7 @@ namespace OpenSim.Framework.Servers MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId); else MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId); - } + } /// /// Console output is only possible if a console has been established. @@ -1020,13 +1020,13 @@ namespace OpenSim.Framework.Servers m_console.Output(msg); } } - + /// /// Console output is only possible if a console has been established. /// That is something that cannot be determined within this class. So /// all attempts to use the console MUST be verified. /// - /// + /// /// protected void Notice(string format, params object[] components) { diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs index 60533cd960..e5f704381b 100644 --- a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs +++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs @@ -92,87 +92,87 @@ namespace OpenSim.Framework.Servers.Tests public class TestHttpRequest: IHttpRequest { private string _uriPath; - public bool BodyIsComplete - { - get { return true; } + public bool BodyIsComplete + { + get { return true; } } - public string[] AcceptTypes - { + public string[] AcceptTypes + { get {return _acceptTypes; } } private string[] _acceptTypes; - public Stream Body - { - get { return _body; } - set { _body = value;} + public Stream Body + { + get { return _body; } + set { _body = value;} } private Stream _body; - public ConnectionType Connection - { + public ConnectionType Connection + { get { return _connection; } set { _connection = value; } } private ConnectionType _connection; - public int ContentLength - { + public int ContentLength + { get { return _contentLength; } set { _contentLength = value; } } private int _contentLength; - public NameValueCollection Headers - { + public NameValueCollection Headers + { get { return _headers; } } private NameValueCollection _headers = new NameValueCollection(); - public string HttpVersion - { + public string HttpVersion + { get { return _httpVersion; } set { _httpVersion = value; } } private string _httpVersion = null; - public string Method - { + public string Method + { get { return _method; } set { _method = value; } } private string _method = null; - public HttpInput QueryString - { + public HttpInput QueryString + { get { return _queryString; } } private HttpInput _queryString = null; - public Uri Uri - { + public Uri Uri + { get { return _uri; } - set { _uri = value; } + set { _uri = value; } } private Uri _uri = null; - public string[] UriParts - { + public string[] UriParts + { get { return _uri.Segments; } } - public HttpParam Param - { - get { return null; } + public HttpParam Param + { + get { return null; } } - public HttpForm Form - { - get { return null; } + public HttpForm Form + { + get { return null; } } - public bool IsAjax - { - get { return false; } + public bool IsAjax + { + get { return false; } } - public RequestCookies Cookies - { - get { return null; } + public RequestCookies Cookies + { + get { return null; } } public TestHttpRequest() {} - public TestHttpRequest(string contentEncoding, string contentType, string userAgent, + public TestHttpRequest(string contentEncoding, string contentType, string userAgent, string remoteAddr, string remotePort, string[] acceptTypes, - ConnectionType connectionType, int contentLength, Uri uri) + ConnectionType connectionType, int contentLength, Uri uri) { _headers["content-encoding"] = contentEncoding; _headers["content-type"] = contentType; @@ -192,7 +192,7 @@ namespace OpenSim.Framework.Servers.Tests { _headers.Add(name, value); } - public int AddToBody(byte[] bytes, int offset, int length) + public int AddToBody(byte[] bytes, int offset, int length) { return 0; } @@ -223,7 +223,7 @@ namespace OpenSim.Framework.Servers.Tests set { _uriPath = value; - + } } @@ -231,7 +231,7 @@ namespace OpenSim.Framework.Servers.Tests public class TestHttpResponse: IHttpResponse { - public Stream Body + public Stream Body { get { return _body; } @@ -239,14 +239,14 @@ namespace OpenSim.Framework.Servers.Tests } private Stream _body; - public string ProtocolVersion - { + public string ProtocolVersion + { get { return _protocolVersion; } set { _protocolVersion = value; } } private string _protocolVersion; - public bool Chunked + public bool Chunked { get { return _chunked; } @@ -254,7 +254,7 @@ namespace OpenSim.Framework.Servers.Tests } private bool _chunked; - public ConnectionType Connection + public ConnectionType Connection { get { return _connection; } @@ -262,7 +262,7 @@ namespace OpenSim.Framework.Servers.Tests } private ConnectionType _connection; - public Encoding Encoding + public Encoding Encoding { get { return _encoding; } @@ -270,7 +270,7 @@ namespace OpenSim.Framework.Servers.Tests } private Encoding _encoding; - public int KeepAlive + public int KeepAlive { get { return _keepAlive; } @@ -278,7 +278,7 @@ namespace OpenSim.Framework.Servers.Tests } private int _keepAlive; - public HttpStatusCode Status + public HttpStatusCode Status { get { return _status; } @@ -286,7 +286,7 @@ namespace OpenSim.Framework.Servers.Tests } private HttpStatusCode _status; - public string Reason + public string Reason { get { return _reason; } @@ -294,7 +294,7 @@ namespace OpenSim.Framework.Servers.Tests } private string _reason; - public long ContentLength + public long ContentLength { get { return _contentLength; } @@ -302,7 +302,7 @@ namespace OpenSim.Framework.Servers.Tests } private long _contentLength; - public string ContentType + public string ContentType { get { return _contentType; } @@ -310,19 +310,19 @@ namespace OpenSim.Framework.Servers.Tests } private string _contentType; - public bool HeadersSent + public bool HeadersSent { get { return _headersSent; } } private bool _headersSent; - public bool Sent + public bool Sent { get { return _sent; } } private bool _sent; - public ResponseCookies Cookies + public ResponseCookies Cookies { get { return _cookies; } } @@ -335,25 +335,25 @@ namespace OpenSim.Framework.Servers.Tests } public void AddHeader(string name, string value) {} - public void Send() + public void Send() { if (!_headersSent) SendHeaders(); if (_sent) throw new InvalidOperationException("stuff already sent"); _sent = true; } - public void SendBody(byte[] buffer, int offset, int count) + public void SendBody(byte[] buffer, int offset, int count) { if (!_headersSent) SendHeaders(); _sent = true; } - public void SendBody(byte[] buffer) + public void SendBody(byte[] buffer) { if (!_headersSent) SendHeaders(); _sent = true; } - public void SendHeaders() + public void SendHeaders() { if (_headersSent) throw new InvalidOperationException("headers already sent"); _headersSent = true; @@ -362,7 +362,7 @@ namespace OpenSim.Framework.Servers.Tests public void Redirect(Uri uri) {} public void Redirect(string url) {} } - + public OSHttpRequest req0; public OSHttpRequest req1; @@ -374,22 +374,22 @@ namespace OpenSim.Framework.Servers.Tests [TestFixtureSetUp] public void Init() { - TestHttpRequest threq0 = new TestHttpRequest("utf-8", "text/xml", "OpenSim Test Agent", "192.168.0.1", "4711", - new string[] {"text/xml"}, - ConnectionType.KeepAlive, 4711, + TestHttpRequest threq0 = new TestHttpRequest("utf-8", "text/xml", "OpenSim Test Agent", "192.168.0.1", "4711", + new string[] {"text/xml"}, + ConnectionType.KeepAlive, 4711, new Uri("http://127.0.0.1/admin/inventory/Dr+Who/Tardis")); threq0.Method = "GET"; threq0.HttpVersion = HttpHelper.HTTP10; - TestHttpRequest threq1 = new TestHttpRequest("utf-8", "text/xml", "OpenSim Test Agent", "192.168.0.1", "4711", - new string[] {"text/xml"}, - ConnectionType.KeepAlive, 4711, + TestHttpRequest threq1 = new TestHttpRequest("utf-8", "text/xml", "OpenSim Test Agent", "192.168.0.1", "4711", + new string[] {"text/xml"}, + ConnectionType.KeepAlive, 4711, new Uri("http://127.0.0.1/admin/inventory/Dr+Who/Tardis?a=0&b=1&c=2")); threq1.Method = "POST"; threq1.HttpVersion = HttpHelper.HTTP11; threq1.Headers["x-wuff"] = "wuffwuff"; threq1.Headers["www-authenticate"] = "go away"; - + req0 = new OSHttpRequest(new TestHttpClientContext(false), threq0); req1 = new OSHttpRequest(new TestHttpClientContext(false), threq1); diff --git a/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs b/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs index 512ac4f722..9126cfb5f4 100644 --- a/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs +++ b/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs @@ -56,7 +56,7 @@ namespace OpenSim.Framework.ServiceAuth { // remove_me = section; m_Username = Util.GetConfigVarFromSections(config, "HttpAuthUsername", new string[] { "Network", section }, string.Empty); - m_Password = Util.GetConfigVarFromSections(config, "HttpAuthPassword", new string[] { "Network", section }, string.Empty); + m_Password = Util.GetConfigVarFromSections(config, "HttpAuthPassword", new string[] { "Network", section }, string.Empty); string str = m_Username + ":" + m_Password; byte[] encData_byte = Util.UTF8.GetBytes(str); diff --git a/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs index a49952c513..79d6ff429b 100644 --- a/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs +++ b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs @@ -56,7 +56,7 @@ namespace OpenSim.Framework.ServiceAuth m_authentications.Remove(auth); } - public void AddAuthorization(NameValueCollection headers) + public void AddAuthorization(NameValueCollection headers) { foreach (IServiceAuth auth in m_authentications) auth.AddAuthorization(headers); diff --git a/OpenSim/Framework/SimStats.cs b/OpenSim/Framework/SimStats.cs index a811187265..f19a270e59 100644 --- a/OpenSim/Framework/SimStats.cs +++ b/OpenSim/Framework/SimStats.cs @@ -32,7 +32,7 @@ namespace OpenSim.Framework { /// /// Enapsulate statistics for a simulator/scene. - /// + /// /// TODO: This looks very much like the OpenMetaverse SimStatsPacket. It should be much more generic stats /// storage. /// @@ -49,7 +49,7 @@ namespace OpenSim.Framework get { return m_regionY; } } private uint m_regionY; - + public SimStatsPacket.RegionBlock RegionBlock { get { return m_regionBlock; } @@ -73,7 +73,7 @@ namespace OpenSim.Framework get { return m_regionFlags; } } private uint m_regionFlags; - + public uint ObjectCapacity { get { return m_objectCapacity; } @@ -85,9 +85,9 @@ namespace OpenSim.Framework get { return regionUUID; } } private UUID regionUUID; - + public SimStats( - uint regionX, uint regionY, uint regionFlags, uint objectCapacity, + uint regionX, uint regionY, uint regionFlags, uint objectCapacity, SimStatsPacket.RegionBlock regionBlock, SimStatsPacket.StatBlock[] statsBlock, SimStatsPacket.StatBlock[] ExtraStatsBlock, UUID pRUUID) { diff --git a/OpenSim/Framework/TaskInventoryDictionary.cs b/OpenSim/Framework/TaskInventoryDictionary.cs index c270d98ee7..223d91f3a6 100644 --- a/OpenSim/Framework/TaskInventoryDictionary.cs +++ b/OpenSim/Framework/TaskInventoryDictionary.cs @@ -52,7 +52,7 @@ namespace OpenSim.Framework private static XmlSerializer tiiSerializer = new XmlSerializer(typeof (TaskInventoryItem)); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private Thread LockedByThread; // private string WriterStack; @@ -98,7 +98,7 @@ namespace OpenSim.Framework if (!LockedByThread.IsAlive) { //Locked by dead thread, reset. - m_itemLock = new System.Threading.ReaderWriterLockSlim(); + m_itemLock = new System.Threading.ReaderWriterLockSlim(); } } @@ -146,7 +146,7 @@ namespace OpenSim.Framework // {} m_itemLock.ExitWriteLock(); } - + while (!m_itemLock.TryEnterReadLock(60000)) { m_log.Error("Thread lock detected while trying to aquire READ lock in TaskInventoryDictionary. Locked by thread " + LockedByThread.Name + ". I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed."); diff --git a/OpenSim/Framework/TaskInventoryItem.cs b/OpenSim/Framework/TaskInventoryItem.cs index b195bbe237..1cc32b3407 100644 --- a/OpenSim/Framework/TaskInventoryItem.cs +++ b/OpenSim/Framework/TaskInventoryItem.cs @@ -73,7 +73,7 @@ namespace OpenSim.Framework private UUID _loadedID = UUID.Zero; private bool _ownerChanged = false; - + public UUID AssetID { get { return _assetID; diff --git a/OpenSim/Framework/Tests/AgentCircuitDataTest.cs b/OpenSim/Framework/Tests/AgentCircuitDataTest.cs index e8ae728b2e..5ad0030ed8 100644 --- a/OpenSim/Framework/Tests/AgentCircuitDataTest.cs +++ b/OpenSim/Framework/Tests/AgentCircuitDataTest.cs @@ -96,7 +96,7 @@ namespace OpenSim.Framework.Tests VisualParams[(int)AvatarAppearance.VPElement.SHAPE_FOOT_SIZE] = 45; - // head + // head VisualParams[(int)AvatarAppearance.VPElement.SHAPE_HEAD_SIZE] = 255; VisualParams[(int)AvatarAppearance.VPElement.SHAPE_SQUASH_STRETCH_HEAD] = 0; // head stretch VisualParams[(int)AvatarAppearance.VPElement.SHAPE_HEAD_SHAPE] = 155; @@ -106,7 +106,7 @@ namespace OpenSim.Framework.Tests VisualParams[(int)AvatarAppearance.VPElement.SHAPE_FACE_SHEAR] = 127; VisualParams[(int)AvatarAppearance.VPElement.SHAPE_FOREHEAD_ANGLE] = 104; VisualParams[(int)AvatarAppearance.VPElement.SHAPE_BIG_BROW] = 94; - VisualParams[(int)AvatarAppearance.VPElement.SHAPE_PUFFY_UPPER_CHEEKS] = 0; // upper cheeks + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_PUFFY_UPPER_CHEEKS] = 0; // upper cheeks VisualParams[(int)AvatarAppearance.VPElement.SHAPE_DOUBLE_CHIN] = 122; // lower cheeks VisualParams[(int)AvatarAppearance.VPElement.SHAPE_HIGH_CHEEK_BONES] = 130; @@ -232,7 +232,7 @@ namespace OpenSim.Framework.Tests /// /// Test to ensure that the serialization format is the same and the underlying types don't change without notice /// oldSerialization is just a json serialization of the OSDMap packed for the AgentCircuitData. - /// The idea is that if the current json serializer cannot parse the old serialization, then the underlying types + /// The idea is that if the current json serializer cannot parse the old serialization, then the underlying types /// have changed and are incompatible. /// [Test] @@ -319,7 +319,7 @@ namespace OpenSim.Framework.Tests string str = OSDParser.SerializeJsonString(map); //System.Console.WriteLine(str); map2 = (OSDMap) OSDParser.DeserializeJson(str); - } + } catch (System.NullReferenceException) { //spurious litjson errors :P diff --git a/OpenSim/Framework/Tests/AgentCircuitManagerTests.cs b/OpenSim/Framework/Tests/AgentCircuitManagerTests.cs index ae132c8c8b..b572afcdea 100644 --- a/OpenSim/Framework/Tests/AgentCircuitManagerTests.cs +++ b/OpenSim/Framework/Tests/AgentCircuitManagerTests.cs @@ -183,7 +183,7 @@ namespace OpenSim.Framework.Tests resp = agentCircuitManager.AuthenticateSession(UUID.Random(), AgentId1, circuitcode1); Assert.That(!resp.Authorised); - + resp = agentCircuitManager.AuthenticateSession(SessionId1, AgentId1, circuitcode2); Assert.That(!resp.Authorised); diff --git a/OpenSim/Framework/Tests/AnimationTests.cs b/OpenSim/Framework/Tests/AnimationTests.cs index d8f17d021e..daf8611875 100644 --- a/OpenSim/Framework/Tests/AnimationTests.cs +++ b/OpenSim/Framework/Tests/AnimationTests.cs @@ -84,7 +84,7 @@ namespace OpenSim.Framework.Tests anim4.AnimID = anim2.AnimID; anim4.ObjectID = anim2.ObjectID; anim4.SequenceNum = anim2.SequenceNum; - + Assert.That(anim4.ObjectID == objUUID2 && anim4.AnimID == animUUID2 && anim4.SequenceNum == 1, "void constructor and manual field population failed to set the properties correctly."); } } diff --git a/OpenSim/Framework/Tests/CacheTests.cs b/OpenSim/Framework/Tests/CacheTests.cs index c709860a85..a92ff3c036 100644 --- a/OpenSim/Framework/Tests/CacheTests.cs +++ b/OpenSim/Framework/Tests/CacheTests.cs @@ -70,7 +70,7 @@ namespace OpenSim.Framework.Tests Assert.That(citem == null, "Item should not be in Cache"); } - + [Test] public void ExpireItemManually() { @@ -96,7 +96,7 @@ namespace OpenSim.Framework.Tests cachedItem.Store(foo); cache.Store(cacheItemUUID.ToString(), cachedItem); cache.Clear(); - + object citem = cache.Get(cacheItemUUID.ToString()); Assert.That(citem == null, "Item should not be in Cache because we manually invalidated it"); } diff --git a/OpenSim/Framework/Tests/LocationTest.cs b/OpenSim/Framework/Tests/LocationTest.cs index 3d5d1d275b..5e84026708 100644 --- a/OpenSim/Framework/Tests/LocationTest.cs +++ b/OpenSim/Framework/Tests/LocationTest.cs @@ -85,6 +85,6 @@ namespace OpenSim.Framework.Tests Assert.That(TestLocation2.Equals(cln), "Cloned object failed .Equals(obj) Test"); } - + } } diff --git a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs index d8072c7829..bde705690f 100644 --- a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs +++ b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs @@ -110,7 +110,7 @@ namespace OpenSim.Framework.Tests && position2.Center == position1.Center && position2.RegionHandle == position1.RegionHandle && position2.Far == position1.Far - + ,"Copy From ChildAgentDataUpdate failed"); position2 = new AgentPosition(); @@ -148,13 +148,13 @@ namespace OpenSim.Framework.Tests // string time = settings.LoadedCreationTime; Assert.That(m_RegionSettingsOnSaveEventFired, "RegionSettings Save Event didn't Fire"); - + } public void RegionSaveFired(RegionSettings settings) { m_RegionSettingsOnSaveEventFired = true; } - + [Test] public void InventoryItemBaseConstructorTest01() { @@ -164,7 +164,7 @@ namespace OpenSim.Framework.Tests UUID ItemID = UUID.Random(); UUID OwnerID = UUID.Random(); - + InventoryItemBase b2 = new InventoryItemBase(ItemID); Assert.That(b2.ID == ItemID, "ID constructor should create an inventory item with ID = ItemID"); Assert.That(b2.Owner == UUID.Zero, "ID constructor should create an inventory item with Owner = UUID.Zero"); @@ -268,7 +268,7 @@ namespace OpenSim.Framework.Tests Assert.That(fld.ID == uuid1, "ID,Owner constructor failed to save value in ID field."); Assert.That(fld.Owner == uuid2, "ID,Owner constructor failed to save value in ID field."); } - + [Test] public void AsssetBaseConstructorTest01() { @@ -304,6 +304,6 @@ namespace OpenSim.Framework.Tests Culture.SetCurrentCulture(); Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US"); - } + } } } diff --git a/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs b/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs index 82e13e5bc4..cc30fb97d6 100644 --- a/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs +++ b/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs @@ -127,9 +127,9 @@ namespace OpenSim.Framework.Tests int[] nonprimes = { 4, 6, 8, 10, 14, 16, 18, 22, 28, 30, 36, 40, 42, 46, 52, 58, 60, 66, 70, 72, 78, 82, 88, - 96, 366, 372, 378, 382, 388, 396, 400, 408, 418, 420, 430, 432, 438, 442, 448, 456, 460, 462, - 466, 478, 486, 490, 498, 502, 508, 856, 858, 862, 876, 880, 882, 886, 906, 910, 918, 928, 936, - 940, 946, 952, 966, 970, 976, 982, 990, 996, 1008, 1740, 1746, 1752, 1758, 4650, 4656, 4662, + 96, 366, 372, 378, 382, 388, 396, 400, 408, 418, 420, 430, 432, 438, 442, 448, 456, 460, 462, + 466, 478, 486, 490, 498, 502, 508, 856, 858, 862, 876, 880, 882, 886, 906, 910, 918, 928, 936, + 940, 946, 952, 966, 970, 976, 982, 990, 996, 1008, 1740, 1746, 1752, 1758, 4650, 4656, 4662, 4672, 4678, 4690, 7740, 7752, 7756, 7758, 7788, 7792, 7816, 7822, 7828, 7840, 7852, 7866, 7872, 7876, 7878, 7882, 7900, 7906, 7918 }; diff --git a/OpenSim/Framework/Tests/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs index 14b9d2f08a..b3d79eec97 100644 --- a/OpenSim/Framework/Tests/UtilTest.cs +++ b/OpenSim/Framework/Tests/UtilTest.cs @@ -233,7 +233,7 @@ namespace OpenSim.Framework.Tests "application/vnd.ll.clothing", "application/vnd.ll.gesture" }; - + for (int i=0;i public virtual ulong HomeRegion { - get - { + get + { return Util.RegionWorldLocToHandle(Util.RegionToWorldLoc(m_homeRegionX), Util.RegionToWorldLoc(m_homeRegionY)); - // return Utils.UIntsToLong( m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize); + // return Utils.UIntsToLong( m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize); } - + set { uint regionWorldLocX, regionWorldLocY; @@ -212,7 +212,7 @@ namespace OpenSim.Framework get { return m_surname; } set { m_surname = value; } } - + /// /// The concatentation of the various name components. /// diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs index 4ed890bc43..7c6a6feaae 100644 --- a/OpenSim/Framework/UserProfiles.cs +++ b/OpenSim/Framework/UserProfiles.cs @@ -50,7 +50,7 @@ namespace OpenSim.Framework public byte Flags = 0; public int Price = 0; } - + public class UserProfileProperties { public UUID UserId = UUID.Zero; @@ -68,7 +68,7 @@ namespace OpenSim.Framework public UUID FirstLifeImageId = UUID.Zero; public string FirstLifeText = string.Empty; } - + public class UserProfilePick { public UUID PickId = UUID.Zero; @@ -86,7 +86,7 @@ namespace OpenSim.Framework public int SortOrder = 0; public bool Enabled = false; } - + public class UserProfileNotes { public UUID UserId; @@ -101,7 +101,7 @@ namespace OpenSim.Framework public bool Visible = false; public string EMail = string.Empty; } - + public class UserAccountProperties { public string EmailAddress = string.Empty; @@ -110,13 +110,13 @@ namespace OpenSim.Framework public string Password = string.Empty; public string UserId = string.Empty; } - + public class UserAccountAuth { public string UserId = UUID.Zero.ToString(); public string Password = string.Empty; } - + public class UserAppData { public string TagId = string.Empty; diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 89cf045716..6d679f2c12 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -59,7 +59,7 @@ namespace OpenSim.Framework { [Flags] public enum PermissionMask : uint - { + { None = 0, // folded perms @@ -112,7 +112,7 @@ namespace OpenSim.Framework public STPStartInfo STPStartInfo { get; set; } public WIGStartInfo WIGStartInfo { get; set; } public bool IsIdle { get; set; } - public bool IsShuttingDown { get; set; } + public bool IsShuttingDown { get; set; } public int MaxThreads { get; set; } public int MinThreads { get; set; } public int InUseThreads { get; set; } @@ -230,7 +230,7 @@ namespace OpenSim.Framework public static Encoding UTF8NoBomEncoding = new UTF8Encoding(false); /// - /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) + /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) /// public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f"); @@ -280,7 +280,7 @@ namespace OpenSim.Framework /// /// A 3d vector /// A new vector which is normalized form of the vector - + public static Vector3 GetNormalizedVector(Vector3 a) { Vector3 v = new Vector3(a.X, a.Y, a.Z); @@ -371,7 +371,7 @@ namespace OpenSim.Framework // Regions are identified with a 'handle' made up of its world coordinates packed into a ulong. // Region handles are based on the coordinate of the region corner with lower X and Y // var regions need more work than this to get that right corner from a generic world position - // this corner must be on a grid point + // this corner must be on a grid point public static ulong RegionWorldLocToHandle(uint X, uint Y) { ulong handle = X & 0xffffff00; // make sure it matchs grid coord points. @@ -450,7 +450,7 @@ namespace OpenSim.Framework string host; uint port = 80; - + string[] parts = inputName.Split(new char[] { ':' }); int indx; if(parts.Length == 0) @@ -470,7 +470,7 @@ namespace OpenSim.Framework else { host = parts[0]; - + if (parts.Length >= 2) { indx = parts[1].IndexOf('/'); @@ -875,8 +875,8 @@ namespace OpenSim.Framework /// New region x-coord /// Old region y-coord /// New region y-coord - /// - public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy, + /// + public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy, int oldsizex, int oldsizey, int newsizex, int newsizey) { // we still need to make sure we see new region 1stNeighbors @@ -1267,7 +1267,7 @@ namespace OpenSim.Framework /// /// Gets the value of a configuration variable by looking into - /// multiple sections in order. The latter sections overwrite + /// multiple sections in order. The latter sections overwrite /// any values previously found. /// /// Type of the variable @@ -1282,7 +1282,7 @@ namespace OpenSim.Framework /// /// Gets the value of a configuration variable by looking into - /// multiple sections in order. The latter sections overwrite + /// multiple sections in order. The latter sections overwrite /// any values previously found. /// /// @@ -1338,7 +1338,7 @@ namespace OpenSim.Framework ConfigSource.ExpandKeyValues(); } } - + public static T ReadSettingsFromIniFile(IConfig config, T settingsClass) { Type settingsType = settingsClass.GetType(); @@ -1449,7 +1449,7 @@ namespace OpenSim.Framework if (File.Exists(configFile)) { - // Merge + // Merge config.Merge(new IniConfigSource(configFile)); config.ExpandKeyValues(); configFilePath = configFile; @@ -1598,7 +1598,7 @@ namespace OpenSim.Framework } memory.Position = 0; - + byte[] compressed = new byte[memory.Length]; memory.Read(compressed, 0, compressed.Length); @@ -1645,7 +1645,7 @@ namespace OpenSim.Framework const int readSize = 256; byte[] buffer = new byte[readSize]; MemoryStream ms = new MemoryStream(); - + int count = inputStream.Read(buffer, 0, readSize); while (count > 0) @@ -1731,10 +1731,10 @@ namespace OpenSim.Framework regionHandle = Utils.BytesToUInt64(bytes); x = Utils.BytesToUInt(bytes, 8) & 0xffff; y = Utils.BytesToUInt(bytes, 12) & 0xffff; - // validation may fail, just reducing the odds of using a real UUID as encoded parcel + // validation may fail, just reducing the odds of using a real UUID as encoded parcel return ( bytes[0] == 0 && bytes[4] == 0 && // handler x,y multiples of 256 bytes[9] < 64 && bytes[13] < 64 && // positions < 16km - bytes[14] == 0 && bytes[15] == 0); + bytes[14] == 0 && bytes[15] == 0); } public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z) @@ -1757,7 +1757,7 @@ namespace OpenSim.Framework x += rx; y += ry; } - + /// /// Get operating system information if available. Returns only the first 45 characters of information /// @@ -1776,12 +1776,12 @@ namespace OpenSim.Framework // { // os = ReadEtcIssue(); // } -// +// // if (os.Length > 45) // { // os = os.Substring(0, 45); // } - + return os; } @@ -1993,7 +1993,7 @@ namespace OpenSim.Framework vol = vcomps[0]; } } - + string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries); // Glob @@ -2095,7 +2095,7 @@ namespace OpenSim.Framework if (!str.EndsWith("\0")) str += "\0"; - + // Because this is UTF-8 encoding and not ASCII, it's possible we // might have gotten an oversized array even after the string trim byte[] data = UTF8.GetBytes(str); @@ -2354,7 +2354,7 @@ namespace OpenSim.Framework throw new NotImplementedException(); } } - + /// /// Additional information about threads in the main thread pool. Used to time how long the /// thread has been running, and abort it if it has timed-out. @@ -2365,7 +2365,7 @@ namespace OpenSim.Framework public string StackTrace { get; set; } private string context; public bool LogThread { get; set; } - + public IWorkItemResult WorkItem { get; set; } public Thread Thread { get; set; } public bool Running { get; set; } @@ -2470,7 +2470,7 @@ namespace OpenSim.Framework public static Dictionary GetFireAndForgetCallsMade() { return new Dictionary(m_fireAndForgetCallsMade); - } + } private static Dictionary m_fireAndForgetCallsMade = new Dictionary(); @@ -2490,7 +2490,7 @@ namespace OpenSim.Framework { FireAndForget(callback, obj, null); } - + public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context) { Interlocked.Increment(ref numTotalThreadFuncsCalled); @@ -2511,19 +2511,19 @@ namespace OpenSim.Framework WaitCallback realCallback; bool loggingEnabled = LogThreadPool > 0; - + long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum); ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context); if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) { // If we're running regression tests, then we want any exceptions to rise up to the test code. - realCallback = - o => - { - Culture.SetCurrentCulture(); - callback(o); - + realCallback = + o => + { + Culture.SetCurrentCulture(); + callback(o); + if (context != null) m_fireAndForgetCallsInProgress[context]--; }; @@ -2666,7 +2666,7 @@ namespace OpenSim.Framework if (stackTrace.Contains("BeginFireQueueEmpty")) return false; } - + return true; } @@ -2679,7 +2679,7 @@ namespace OpenSim.Framework { string src = Environment.StackTrace; string[] lines = src.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); - + StringBuilder dest = new StringBuilder(src.Length); bool started = false; @@ -2724,11 +2724,11 @@ namespace OpenSim.Framework /// trace. And pausing another thread can cause a deadlock. This method attempts to /// avoid deadlock by using a short timeout (200ms), after which it gives up and /// returns 'null' instead of the stack trace. - /// + /// /// Take from: http://stackoverflow.com/a/14935378 - /// + /// /// WARNING: this doesn't work in Mono. See https://bugzilla.novell.com/show_bug.cgi?id=571691 - /// + /// /// /// The stack trace, or null if failed to get it private static StackTrace GetStackTrace(Thread targetThread) @@ -2829,7 +2829,7 @@ namespace OpenSim.Framework /// /// Environment.TickCount is an int but it counts all 32 bits so it goes positive /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap - /// for the callers. + /// for the callers. /// This trims it to a 12 day interval so don't let your frame time get too long. /// /// @@ -3186,7 +3186,7 @@ namespace OpenSim.Framework if (parts.Length == 2) return CalcUniversalIdentifier(id, agentsURI, parts[0] + " " + parts[1]); } - + return CalcUniversalIdentifier(id, agentsURI, firstName + " " + lastName); } @@ -3286,10 +3286,10 @@ namespace OpenSim.Framework public virtual int Count { - get - { + get + { lock (m_syncRoot) - return m_highQueue.Count + m_lowQueue.Count; + return m_highQueue.Count + m_lowQueue.Count; } } diff --git a/OpenSim/Framework/VersionInfo.cs b/OpenSim/Framework/VersionInfo.cs index 7bb0351ea1..1e6efe54ef 100644 --- a/OpenSim/Framework/VersionInfo.cs +++ b/OpenSim/Framework/VersionInfo.cs @@ -58,10 +58,10 @@ namespace OpenSim } public const int VERSIONINFO_VERSION_LENGTH = 27; - + /// /// This is the external interface version. It is separate from the OpenSimulator project version. - /// + /// /// /// Commented because it's not used anymore, see below for new /// versioning method. @@ -70,18 +70,18 @@ namespace OpenSim /// /// This rules versioning regarding teleports, and compatibility between simulators in that regard. /// - /// + /// /// /// The protocol version that we will use for outgoing transfers - /// Valid values are - /// "SIMULATION/0.3" + /// Valid values are + /// "SIMULATION/0.3" /// - This is the latest, and it supports teleports to variable-sized regions /// - Older versions can teleport to this one, but only if the destination region /// is 256x256 /// "SIMULATION/0.2" /// - A source simulator which only implements "SIMULATION/0.1" can still teleport here /// - this protocol is more efficient than "SIMULATION/0.1" - /// "SIMULATION/0.1" + /// "SIMULATION/0.1" /// - this is an older teleport protocol used in OpenSimulator 0.7.5 and before. /// public readonly static float SimulationServiceVersionAcceptedMin = 0.3f; diff --git a/OpenSim/Framework/WearableCacheItem.cs b/OpenSim/Framework/WearableCacheItem.cs index 966a6bc290..ccaf69edfd 100644 --- a/OpenSim/Framework/WearableCacheItem.cs +++ b/OpenSim/Framework/WearableCacheItem.cs @@ -47,7 +47,7 @@ namespace OpenSim.Framework WearableCacheItem[] retitems = new WearableCacheItem[itemmax]; for (uint i=0;i: {1}",response,e.Message); } - + return result; } - + #endregion JSONRequest #region FormRequest @@ -419,7 +419,7 @@ namespace OpenSim.Framework { return ServiceFormRequest(url,data, 30000); } - + public static OSDMap ServiceFormRequest(string url, NameValueCollection data, int timeout) { lock (EndPointLock(url)) @@ -436,7 +436,7 @@ namespace OpenSim.Framework if (DebugLevel >= 3) m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} ServiceForm '{1}' to {2}", reqnum, method, url); - + string errorMessage = "unknown error"; int tickstart = Util.EnvironmentTickCount(); int tickdata = 0; @@ -451,7 +451,7 @@ namespace OpenSim.Framework request.MaximumAutomaticRedirections = 10; request.ReadWriteTimeout = timeout / 4; request.Headers[OSHeaderRequestID] = reqnum.ToString(); - + if (data != null) { queryString = BuildQueryString(data); @@ -460,7 +460,7 @@ namespace OpenSim.Framework LogOutgoingDetail("SEND", reqnum, queryString); byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString); - + request.ContentLength = buffer.Length; request.ContentType = "application/x-www-form-urlencoded"; using (Stream requestStream = request.GetRequestStream()) @@ -538,7 +538,7 @@ namespace OpenSim.Framework } #endregion FormRequest - + #region Uri /// @@ -591,7 +591,7 @@ namespace OpenSim.Framework } /// - /// Appends a query string to a Uri that may or may not have existing + /// Appends a query string to a Uri that may or may not have existing /// query parameters /// /// Uri to append the query to @@ -643,7 +643,7 @@ namespace OpenSim.Framework } /// - /// + /// /// /// /// @@ -662,12 +662,12 @@ namespace OpenSim.Framework #region Stream /// - /// Copies the contents of one stream to another, starting at the + /// Copies the contents of one stream to another, starting at the /// current position of each stream /// - /// The stream to copy from, at the position + /// The stream to copy from, at the position /// where copying should begin - /// The stream to copy to, at the position where + /// The stream to copy to, at the position where /// bytes should be written /// The maximum bytes to copy /// The total number of bytes copied @@ -811,7 +811,7 @@ namespace OpenSim.Framework /// /// /// - /// The response. If there was an internal exception or the request timed out, + /// The response. If there was an internal exception or the request timed out, /// then the default(TResponse) is returned. /// public static void MakeRequest(string verb, @@ -909,7 +909,7 @@ namespace OpenSim.Framework // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't // documented in MSDN using (WebResponse response = request.EndGetResponse(res2)) - { + { try { using (Stream respStream = response.GetResponseStream()) @@ -930,7 +930,7 @@ namespace OpenSim.Framework if (e.Response is HttpWebResponse) { using (HttpWebResponse httpResponse = (HttpWebResponse)e.Response) - { + { if (httpResponse.StatusCode != HttpStatusCode.NotFound) { // We don't appear to be handling any other status codes, so log these feailures to that @@ -955,7 +955,7 @@ namespace OpenSim.Framework "[ASYNC REQUEST]: Request {0} {1} failed with exception {2}{3}", verb, requestUrl, e.Message, e.StackTrace); } - + // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString()); try @@ -968,7 +968,7 @@ namespace OpenSim.Framework "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}{3}", verb, requestUrl, e.Message, e.StackTrace); } - + }, null); } @@ -997,7 +997,7 @@ namespace OpenSim.Framework } } finally - { + { if (buffer != null) buffer.Dispose(); } @@ -1168,7 +1168,7 @@ namespace OpenSim.Framework /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds) /// /// - /// The response. If there was an internal exception or the request timed out, + /// The response. If there was an internal exception or the request timed out, /// then the default(TResponse) is returned. /// public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, int pTimeout) @@ -1191,7 +1191,7 @@ namespace OpenSim.Framework /// /// /// - /// The response. If there was an internal exception or the request timed out, + /// The response. If there was an internal exception or the request timed out, /// then the default(TResponse) is returned. /// public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections) @@ -1210,7 +1210,7 @@ namespace OpenSim.Framework /// /// /// - /// The response. If there was an internal exception or the request timed out, + /// The response. If there was an internal exception or the request timed out, /// then the default(TResponse) is returned. /// public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections, IServiceAuth auth) @@ -1375,7 +1375,7 @@ namespace OpenSim.Framework return deserial; } - + public static class XMLResponseHelper { public static TResponse LogAndDeserialize(int reqnum, Stream respStream, long contentLength) @@ -1400,7 +1400,7 @@ namespace OpenSim.Framework } } - + public static class XMLRPCRequester { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -1444,7 +1444,7 @@ namespace OpenSim.Framework { m_log.Error("Error parsing XML-RPC response", e); } - + if (Resp.IsFault) { m_log.DebugFormat( diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs index e441cc8066..5cb6a88e94 100644 --- a/OpenSim/Region/Application/Application.cs +++ b/OpenSim/Region/Application/Application.cs @@ -86,9 +86,9 @@ namespace OpenSim if (logConfigFile != String.Empty) { XmlConfigurator.Configure(new System.IO.FileInfo(logConfigFile)); - m_log.InfoFormat("[OPENSIM MAIN]: configured log4net using \"{0}\" as configuration file", + m_log.InfoFormat("[OPENSIM MAIN]: configured log4net using \"{0}\" as configuration file", logConfigFile); - } + } else { XmlConfigurator.Configure(); @@ -104,22 +104,22 @@ namespace OpenSim "[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset"); // Verify the Threadpool allocates or uses enough worker and IO completion threads - // .NET 2.0, workerthreads default to 50 * numcores - // .NET 3.0, workerthreads defaults to 250 * numcores - // .NET 4.0, workerthreads are dynamic based on bitness and OS resources + // .NET 2.0, workerthreads default to 50 * numcores + // .NET 3.0, workerthreads defaults to 250 * numcores + // .NET 4.0, workerthreads are dynamic based on bitness and OS resources // Max IO Completion threads are 1000 on all 3 CLRs // // Mono 2.10.9 to at least Mono 3.1, workerthreads default to 100 * numcores, iocp threads to 4 * numcores - int workerThreadsMin = 500; - int workerThreadsMax = 1000; // may need further adjustment to match other CLR - int iocpThreadsMin = 1000; - int iocpThreadsMax = 2000; // may need further adjustment to match other CLR + int workerThreadsMin = 500; + int workerThreadsMax = 1000; // may need further adjustment to match other CLR + int iocpThreadsMin = 1000; + int iocpThreadsMax = 2000; // may need further adjustment to match other CLR { int currentMinWorkerThreads, currentMinIocpThreads; System.Threading.ThreadPool.GetMinThreads(out currentMinWorkerThreads, out currentMinIocpThreads); m_log.InfoFormat( - "[OPENSIM MAIN]: Runtime gave us {0} min worker threads and {1} min IOCP threads", + "[OPENSIM MAIN]: Runtime gave us {0} min worker threads and {1} min IOCP threads", currentMinWorkerThreads, currentMinIocpThreads); } @@ -138,30 +138,30 @@ namespace OpenSim m_log.InfoFormat("[OPENSIM MAIN]: Limiting max worker threads to {0}",workerThreads); } - // Increase the number of IOCP threads available. - // Mono defaults to a tragically low number (24 on 6-core / 8GB Fedora 17) - if (iocpThreads < iocpThreadsMin) + // Increase the number of IOCP threads available. + // Mono defaults to a tragically low number (24 on 6-core / 8GB Fedora 17) + if (iocpThreads < iocpThreadsMin) { iocpThreads = iocpThreadsMin; m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max IOCP threads to {0}",iocpThreads); } - // Make sure we don't overallocate IOCP threads and thrash system resources + // Make sure we don't overallocate IOCP threads and thrash system resources if ( iocpThreads > iocpThreadsMax ) { iocpThreads = iocpThreadsMax; m_log.InfoFormat("[OPENSIM MAIN]: Limiting max IOCP completion threads to {0}",iocpThreads); } - // set the resulting worker and IO completion thread counts back to ThreadPool + // set the resulting worker and IO completion thread counts back to ThreadPool if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) ) - { - m_log.InfoFormat( + { + m_log.InfoFormat( "[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IOCP threads", workerThreads, iocpThreads); - } - else - { - m_log.Warn("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect."); - } + } + else + { + m_log.Warn("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect."); + } // Check if the system is compatible with OpenSimulator. // Ensures that the minimum system requirements are met @@ -179,7 +179,7 @@ namespace OpenSim Culture.SetCurrentCulture(); // Validate that the user has the most basic configuration done - // If not, offer to do the most basic configuration for them warning them along the way of the importance of + // If not, offer to do the most basic configuration for them warning them along the way of the importance of // reading these files. /* m_log.Info("Checking for reguired configuration...\n"); @@ -188,13 +188,13 @@ namespace OpenSim || (File.Exists(Path.Combine(Util.configDir(), "opensim.ini"))) || (File.Exists(Path.Combine(Util.configDir(), "openSim.ini"))) || (File.Exists(Path.Combine(Util.configDir(), "Opensim.ini"))); - + bool StanaloneCommon_ProperCased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "StandaloneCommon.ini")); bool StanaloneCommon_lowercased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "standalonecommon.ini")); bool GridCommon_ProperCased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "GridCommon.ini")); bool GridCommon_lowerCased = File.Exists(Path.Combine(Path.Combine(Util.configDir(), "config-include"), "gridcommon.ini")); - if ((OpenSim_Ini) + if ((OpenSim_Ini) && ( (StanaloneCommon_ProperCased || StanaloneCommon_lowercased @@ -212,7 +212,7 @@ namespace OpenSim "yes"); if (resp == "yes") { - + if (!(OpenSim_Ini)) { try @@ -312,7 +312,7 @@ namespace OpenSim m_saveCrashDumps = configSource.Configs["Startup"].GetBoolean("save_crashes", false); // load Crash directory config - m_crashDir = configSource.Configs["Startup"].GetString("crash_dir", m_crashDir); + m_crashDir = configSource.Configs["Startup"].GetString("crash_dir", m_crashDir); if (background) { @@ -320,9 +320,9 @@ namespace OpenSim m_sim.Startup(); } else - { + { m_sim = new OpenSim(configSource); - + m_sim.Startup(); while (true) diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs index 4f141a6e70..62bd4f4ab6 100644 --- a/OpenSim/Region/Application/ConfigurationLoader.cs +++ b/OpenSim/Region/Application/ConfigurationLoader.cs @@ -43,10 +43,10 @@ namespace OpenSim public class ConfigurationLoader { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + /// /// Various Config settings the region needs to start - /// Physics Engine, Mesh Engine, GridMode, PhysicsPrim allowed, Neighbor, + /// Physics Engine, Mesh Engine, GridMode, PhysicsPrim allowed, Neighbor, /// StorageDLL, Storage Connection String, Estate connection String, Client Stack /// Standalone settings. /// @@ -188,7 +188,7 @@ namespace OpenSim { iniFileExists = true; AddIncludes(overrideConfig, overrideSources); - } + } } m_config.Source.Merge(overrideConfig.Source); } @@ -198,7 +198,7 @@ namespace OpenSim { m_log.FatalFormat("[CONFIG]: Could not load any configuration"); Environment.Exit(1); - } + } else if (!iniFileExists) { m_log.FatalFormat("[CONFIG]: Could not load any configuration"); @@ -257,14 +257,14 @@ namespace OpenSim string path = Path.Combine(basepath, chunkWithoutWildcards); path = Path.GetFullPath(path) + chunkWithWildcards; string[] paths = Util.Glob(path); - + // If the include path contains no wildcards, then warn the user that it wasn't found. if (wildcardIndex == -1 && paths.Length == 0) { m_log.WarnFormat("[CONFIG]: Could not find include file {0}", path); } else - { + { foreach (string p in paths) { if (!sources.Contains(p)) @@ -377,7 +377,7 @@ namespace OpenSim m_configSettings.PhysicsEngine = startupConfig.GetString("physics"); m_configSettings.MeshEngineName = startupConfig.GetString("meshing"); - m_configSettings.ClientstackDll + m_configSettings.ClientstackDll = startupConfig.GetString("clientstack_plugin", "OpenSim.Region.ClientStack.LindenUDP.dll"); } diff --git a/OpenSim/Region/Application/IApplicationPlugin.cs b/OpenSim/Region/Application/IApplicationPlugin.cs index a3fa66cc06..ff3f5d7bb9 100644 --- a/OpenSim/Region/Application/IApplicationPlugin.cs +++ b/OpenSim/Region/Application/IApplicationPlugin.cs @@ -43,7 +43,7 @@ namespace OpenSim void Initialise(OpenSimBase openSim); /// - /// Called when the application loading is completed + /// Called when the application loading is completed /// void PostInitialise(); } diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index d9fdcde732..8022b1e587 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -135,7 +135,7 @@ namespace OpenSim { // Wait for a signal to be delivered int index = Mono.Unix.UnixSignal.WaitAny (signals, -1); - + //Mono.Unix.Native.Signum signal = signals [index].Signum; MainConsole.Instance.RunCommand("shutdown"); } @@ -273,17 +273,17 @@ namespace OpenSim m_console.Commands.AddCommand("General", false, "change region", "change region ", - "Change current console region", + "Change current console region", ChangeSelectedRegion); m_console.Commands.AddCommand("Archiving", false, "save xml", "save xml []", - "Save a region's data in XML format", + "Save a region's data in XML format", SaveXml); m_console.Commands.AddCommand("Archiving", false, "save xml2", "save xml2 []", - "Save a region's data in XML2 format", + "Save a region's data in XML2 format", SaveXml2); m_console.Commands.AddCommand("Archiving", false, "load xml", @@ -293,12 +293,12 @@ namespace OpenSim m_console.Commands.AddCommand("Archiving", false, "load xml2", "load xml2 []", - "Load a region's data from XML2 format", + "Load a region's data from XML2 format", LoadXml2); m_console.Commands.AddCommand("Archiving", false, "save prims xml2", "save prims xml2 [ ]", - "Save named prim to XML2", + "Save named prim to XML2", SavePrimsXml2); m_console.Commands.AddCommand("Archiving", false, "load oar", @@ -352,7 +352,7 @@ namespace OpenSim m_console.Commands.AddCommand("Objects", false, "edit scale", "edit scale ", - "Change the scale of a named prim", + "Change the scale of a named prim", HandleEditScale); m_console.Commands.AddCommand("Objects", false, "rotate scene", @@ -379,44 +379,44 @@ namespace OpenSim m_console.Commands.AddCommand("Users", false, "show users", "show users [full]", - "Show user data for users currently on the region", + "Show user data for users currently on the region", "Without the 'full' option, only users actually on the region are shown." + " With the 'full' option child agents of users in neighbouring regions are also shown.", HandleShow); m_console.Commands.AddCommand("Comms", false, "show connections", "show connections", - "Show connection data", + "Show connection data", HandleShow); m_console.Commands.AddCommand("Comms", false, "show circuits", "show circuits", - "Show agent circuit data", + "Show agent circuit data", HandleShow); m_console.Commands.AddCommand("Comms", false, "show pending-objects", "show pending-objects", - "Show # of objects on the pending queues of all scene viewers", + "Show # of objects on the pending queues of all scene viewers", HandleShow); m_console.Commands.AddCommand("General", false, "show modules", "show modules", - "Show module data", + "Show module data", HandleShow); m_console.Commands.AddCommand("Regions", false, "show regions", "show regions", - "Show region data", + "Show region data", HandleShow); - + m_console.Commands.AddCommand("Regions", false, "show ratings", "show ratings", - "Show rating data", + "Show rating data", HandleShow); m_console.Commands.AddCommand("Objects", false, "backup", "backup", - "Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.", + "Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.", RunCommand); m_console.Commands.AddCommand("Regions", false, "create region", @@ -430,22 +430,22 @@ namespace OpenSim m_console.Commands.AddCommand("Regions", false, "restart", "restart", - "Restart the currently selected region(s) in this instance", + "Restart the currently selected region(s) in this instance", RunCommand); m_console.Commands.AddCommand("General", false, "command-script", "command-script